X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-i860.c;h=86d84ed638dc4554354627aa6c9ce53c094c6a2f;hb=2571583aed598dd3f9651b53434e5f177a0e3cf7;hp=f2e2b192721a938123c45b4bc4ac463c11005ba9;hpb=252b5132c753830d5fd56823373aed85f2a0db63;p=external%2Fbinutils.git diff --git a/gas/config/tc-i860.c b/gas/config/tc-i860.c index f2e2b19..86d84ed 100644 --- a/gas/config/tc-i860.c +++ b/gas/config/tc-i860.c @@ -1,11 +1,14 @@ -/* tc-i860.c -- Assemble for the I860 - Copyright (C) 1989, 92, 93, 94, 95, 1998 Free Software Foundation, Inc. +/* tc-i860.c -- Assembler for the Intel i860 architecture. + Copyright (C) 1989-2017 Free Software Foundation, Inc. + + Brought back from the dead and completely reworked + by Jason Eckhardt . This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -15,128 +18,134 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "as.h" - +#include "safe-ctype.h" +#include "subsegs.h" #include "opcode/i860.h" +#include "elf/i860.h" -void md_begin (); -void md_number_to_chars (); -void md_assemble (); -char *md_atof (); -void md_convert_frag (); -int md_estimate_size_before_relax (); -void md_number_to_imm (); -void md_number_to_disp (); -void md_number_to_field (); -void md_ri_to_chars (); -static void i860_ip (); -/* void emit_machine_reloc(); */ - -const int md_reloc_size = sizeof (struct relocation_info); -/* void (*md_emit_relocations)() = emit_machine_reloc; */ - -/* handle of the OPCODE hash table */ +/* The opcode hash table. */ static struct hash_control *op_hash = NULL; -static void s_dual (), s_enddual (); -static void s_atmp (); - -const pseudo_typeS - md_pseudo_table[] = -{ - {"dual", s_dual, 4}, - {"enddual", s_enddual, 4}, - {"atmp", s_atmp, 4}, - {NULL, 0, 0}, -}; +/* These characters always start a comment. */ +const char comment_chars[] = "#!/"; -/* This array holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful */ -const char comment_chars[] = "!/"; /* JF removed '|' from comment_chars */ - -/* This array holds the chars that only start a comment at the beginning of - a line. If the line seems to have the form '# 123 filename' - .line and .file directives will appear in the pre-processed output */ -/* Note that input_file.c hand checks for '#' at the beginning of the - first line of the input file. This is because the compiler outputs - #NO_APP at the beginning of its output. */ -/* Also note that comments like this one will always work. */ +/* These characters start a comment at the beginning of a line. */ const char line_comment_chars[] = "#/"; -const char line_separator_chars[] = ""; +const char line_separator_chars[] = ";"; -/* Chars that can be used to separate mant from exp in floating point nums */ +/* Characters that can be used to separate the mantissa from the exponent + in floating point numbers. */ const char EXP_CHARS[] = "eE"; -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ +/* Characters that indicate this number is a floating point constant. + As in 0f12.456 or 0d1.2345e12. */ const char FLT_CHARS[] = "rRsSfFdDxXpP"; -/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be - changed in read.c . Ideally it shouldn't have to know about it at all, - but nothing is ideal around here. - */ -int size_reloc_info = sizeof (struct relocation_info); +/* Register prefix (depends on syntax). */ +static char reg_prefix; -static unsigned char octal[256]; -#define isoctal(c) octal[c] -static unsigned char toHex[256]; +#define MAX_FIXUPS 2 struct i860_it +{ + const char *error; + unsigned long opcode; + enum expand_type expand; + struct i860_fi { - char *error; - unsigned long opcode; - struct nlist *nlistp; expressionS exp; + bfd_reloc_code_real_type reloc; int pcrel; - enum expand_type expand; - enum highlow_type highlow; - enum reloc_type reloc; - } the_insn; + valueT fup; + } fi[MAX_FIXUPS]; +} the_insn; -#if __STDC__ == 1 +/* The current fixup count. */ +static int fc; -static void print_insn (struct i860_it *insn); -static int getExpression (char *str); +static char *expr_end; -#else /* not __STDC__ */ +/* Indicates error if a pseudo operation was expanded after a branch. */ +static char last_expand; -static void print_insn (); -static int getExpression (); +/* If true, then warn if any pseudo operations were expanded. */ +static int target_warn_expand = 0; -#endif /* not __STDC__ */ +/* If true, then XP support is enabled. */ +static int target_xp = 0; + +/* If true, then Intel syntax is enabled (default to AT&T/SVR4 syntax). */ +static int target_intel_syntax = 0; -static char *expr_end; -static char last_expand; /* error if expansion after branch */ +/* Prototypes. */ +static void i860_process_insn (char *); +static void s_dual (int); +static void s_enddual (int); +static void s_atmp (int); +static void s_align_wrapper (int); +static int i860_get_expression (char *); +static bfd_reloc_code_real_type obtain_reloc_for_imm16 (fixS *, long *); +#ifdef DEBUG_I860 +static void print_insn (struct i860_it *); +#endif + +const pseudo_typeS md_pseudo_table[] = +{ + {"align", s_align_wrapper, 0}, + {"dual", s_dual, 0}, + {"enddual", s_enddual, 0}, + {"atmp", s_atmp, 0}, + {NULL, 0, 0}, +}; + +/* Dual-instruction mode handling. */ enum dual { DUAL_OFF = 0, DUAL_ON, DUAL_DDOT, DUAL_ONDDOT, }; -static enum dual dual_mode = DUAL_OFF; /* dual-instruction mode */ +static enum dual dual_mode = DUAL_OFF; +/* Handle ".dual" directive. */ static void -s_dual () /* floating point instructions have dual set */ +s_dual (int ignore ATTRIBUTE_UNUSED) { - dual_mode = DUAL_ON; + if (target_intel_syntax) + dual_mode = DUAL_ON; + else + as_bad (_("Directive .dual available only with -mintel-syntax option")); } +/* Handle ".enddual" directive. */ static void -s_enddual () /* floating point instructions have dual set */ +s_enddual (int ignore ATTRIBUTE_UNUSED) { - dual_mode = DUAL_OFF; + if (target_intel_syntax) + dual_mode = DUAL_OFF; + else + as_bad (_("Directive .enddual available only with -mintel-syntax option")); } -static int atmp = 31; /* temporary register for pseudo's */ +/* Temporary register used when expanding assembler pseudo operations. */ +static int atmp = 31; static void -s_atmp () +s_atmp (int ignore ATTRIBUTE_UNUSED) { - register int temp; + int temp; + + if (! target_intel_syntax) + { + as_bad (_("Directive .atmp available only with -mintel-syntax option")); + demand_empty_rest_of_line (); + return; + } + if (strncmp (input_line_pointer, "sp", 2) == 0) { input_line_pointer += 2; @@ -163,21 +172,55 @@ s_atmp () demand_empty_rest_of_line (); } +/* Handle ".align" directive depending on syntax mode. + AT&T/SVR4 syntax uses the standard align directive. However, + the Intel syntax additionally allows keywords for the alignment + parameter: ".align type", where type is one of {.short, .long, + .quad, .single, .double} representing alignments of 2, 4, + 16, 4, and 8, respectively. */ +static void +s_align_wrapper (int arg) +{ + char *parm = input_line_pointer; + + if (target_intel_syntax) + { + /* Replace a keyword with the equivalent integer so the + standard align routine can parse the directive. */ + if (strncmp (parm, ".short", 6) == 0) + strncpy (parm, " 2", 6); + else if (strncmp (parm, ".long", 5) == 0) + strncpy (parm, " 4", 5); + else if (strncmp (parm, ".quad", 5) == 0) + strncpy (parm, " 16", 5); + else if (strncmp (parm, ".single", 7) == 0) + strncpy (parm, " 4", 7); + else if (strncmp (parm, ".double", 7) == 0) + strncpy (parm, " 8", 7); + + while (*input_line_pointer == ' ') + ++input_line_pointer; + } + + s_align_bytes (arg); +} + /* This function is called once, at assembler startup time. It should - set up all the tables, etc. that the MD part of the assembler will need. */ + set up all the tables and data structures that the MD part of the + assembler will need. */ void -md_begin () +md_begin (void) { - register char *retval = NULL; + const char *retval = NULL; int lose = 0; - register unsigned int i = 0; + unsigned int i = 0; op_hash = hash_new (); - while (i < NUMOPCODES) + while (i860_opcodes[i].name != NULL) { const char *name = i860_opcodes[i].name; - retval = hash_insert (op_hash, name, &i860_opcodes[i]); + retval = hash_insert (op_hash, name, (void *) &i860_opcodes[i]); if (retval != NULL) { fprintf (stderr, _("internal error: can't hash `%s': %s\n"), @@ -188,147 +231,161 @@ md_begin () { if (i860_opcodes[i].match & i860_opcodes[i].lose) { - fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"), + fprintf (stderr, + _("internal error: losing opcode: `%s' \"%s\"\n"), i860_opcodes[i].name, i860_opcodes[i].args); lose = 1; } ++i; } - while (i < NUMOPCODES - && !strcmp (i860_opcodes[i].name, name)); + while (i860_opcodes[i].name != NULL + && strcmp (i860_opcodes[i].name, name) == 0); } if (lose) - as_fatal (_("Broken assembler. No assembly attempted.")); - - for (i = '0'; i < '8'; ++i) - octal[i] = 1; - for (i = '0'; i <= '9'; ++i) - toHex[i] = i - '0'; - for (i = 'a'; i <= 'f'; ++i) - toHex[i] = i + 10 - 'a'; - for (i = 'A'; i <= 'F'; ++i) - toHex[i] = i + 10 - 'A'; + as_fatal (_("Defective assembler. No assembly attempted.")); + + /* Set the register prefix for either Intel or AT&T/SVR4 syntax. */ + reg_prefix = target_intel_syntax ? 0 : '%'; } +/* This is the core of the machine-dependent assembler. STR points to a + machine dependent instruction. This function emits the frags/bytes + it assembles to. */ void -md_assemble (str) - char *str; +md_assemble (char *str) { - char *toP; - int rsd; - int no_opcodes = 1; + char *destp; + int num_opcodes = 1; int i; struct i860_it pseudo[3]; - assert (str); - i860_ip (str); + gas_assert (str); + fc = 0; + + /* Assemble the instruction. */ + i860_process_insn (str); - /* check for expandable flag to produce pseudo-instructions */ - if (the_insn.expand != 0 && the_insn.highlow == NO_SPEC) + /* Check for expandable flag to produce pseudo-instructions. This + is an undesirable feature that should be avoided. */ + if (the_insn.expand != 0 && the_insn.expand != XP_ONLY + && ! (the_insn.fi[0].fup & (OP_SEL_HA | OP_SEL_H | OP_SEL_L | OP_SEL_GOT + | OP_SEL_GOTOFF | OP_SEL_PLT))) { for (i = 0; i < 3; i++) pseudo[i] = the_insn; + fc = 1; switch (the_insn.expand) { case E_DELAY: - no_opcodes = 1; + num_opcodes = 1; break; case E_MOV: - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_op_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 15) && - the_insn.exp.X_add_number >= -(1 << 15))) + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 15) + && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) break; - /* or l%const,r0,ireg_dest */ + + /* Emit "or l%const,r0,ireg_dest". */ pseudo[0].opcode = (the_insn.opcode & 0x001f0000) | 0xe4000000; - pseudo[0].highlow = PAIR; - /* orh h%const,ireg_dest,ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 | - ((the_insn.opcode & 0x001f0000) << 5); - pseudo[1].highlow = HIGH; - no_opcodes = 2; + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + + /* Emit "orh h%const,ireg_dest,ireg_dest". */ + pseudo[1].opcode = (the_insn.opcode & 0x03ffffff) | 0xec000000 + | ((the_insn.opcode & 0x001f0000) << 5); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + + num_opcodes = 2; break; case E_ADDR: - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_op_symbol == NULL) + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 15) + && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) break; - /* orh ha%addr_expr,r0,r31 */ - pseudo[0].opcode = 0xec000000 | (atmp << 16); - pseudo[0].highlow = HIGHADJ; - pseudo[0].reloc = LOW0; /* must overwrite */ - /* l%addr_expr(r31),ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & ~0x003e0000) | (atmp << 21); - pseudo[1].highlow = PAIR; - no_opcodes = 2; + + /* Emit "orh ha%addr_expr,ireg_src2,r31". */ + pseudo[0].opcode = 0xec000000 | (the_insn.opcode & 0x03e00000) + | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_HA); + + /* Emit "l%addr_expr(r31),ireg_dest". We pick up the fixup + information from the original instruction. */ + pseudo[1].opcode = (the_insn.opcode & ~0x03e00000) | (atmp << 21); + pseudo[1].fi[0].fup = the_insn.fi[0].fup | OP_SEL_L; + + num_opcodes = 2; break; - case E_U32: /* 2nd version emulates Intel as, not doc. */ - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_op_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 16) && - the_insn.exp.X_add_number >= 0)) + case E_U32: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 16) + && the_insn.fi[0].exp.X_add_number >= 0)) break; - /* $(opcode)h h%const,ireg_src2,ireg_dest - pseudo[0].opcode = (the_insn.opcode & 0xf3ffffff) | 0x0c000000; */ - /* $(opcode)h h%const,ireg_src2,r31 */ - pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 | - (atmp << 16); - pseudo[0].highlow = HIGH; - /* $(opcode) l%const,ireg_dest,ireg_dest - pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | - ((the_insn.opcode & 0x001f0000) << 5); */ - /* $(opcode) l%const,r31,ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 | - (atmp << 21); - pseudo[1].highlow = PAIR; - no_opcodes = 2; + + /* Emit "$(opcode)h h%const,ireg_src2,r31". */ + pseudo[0].opcode = (the_insn.opcode & 0xf3e0ffff) | 0x0c000000 + | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + + /* Emit "$(opcode) l%const,r31,ireg_dest". */ + pseudo[1].opcode = (the_insn.opcode & 0xf01f0000) | 0x04000000 + | (atmp << 21); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + + num_opcodes = 2; break; - case E_AND: /* 2nd version emulates Intel as, not doc. */ - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_op_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 16) && - the_insn.exp.X_add_number >= 0)) + case E_AND: + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 16) + && the_insn.fi[0].exp.X_add_number >= 0)) break; - /* andnot h%const,ireg_src2,ireg_dest - pseudo[0].opcode = (the_insn.opcode & 0x03ffffff) | 0xd4000000; */ - /* andnot h%const,ireg_src2,r31 */ - pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 | - (atmp << 16); - pseudo[0].highlow = HIGH; - pseudo[0].exp.X_add_number = -1 - the_insn.exp.X_add_number; - /* andnot l%const,ireg_dest,ireg_dest - pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | - ((the_insn.opcode & 0x001f0000) << 5); */ - /* andnot l%const,r31,ireg_dest */ - pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 | - (atmp << 21); - pseudo[1].highlow = PAIR; - pseudo[1].exp.X_add_number = -1 - the_insn.exp.X_add_number; - no_opcodes = 2; + + /* Emit "andnot h%const,ireg_src2,r31". */ + pseudo[0].opcode = (the_insn.opcode & 0x03e0ffff) | 0xd4000000 + | (atmp << 16); + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + pseudo[0].fi[0].exp.X_add_number = + -1 - the_insn.fi[0].exp.X_add_number; + + /* Emit "andnot l%const,r31,ireg_dest". */ + pseudo[1].opcode = (the_insn.opcode & 0x001f0000) | 0xd4000000 + | (atmp << 21); + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + pseudo[1].fi[0].exp.X_add_number = + -1 - the_insn.fi[0].exp.X_add_number; + + num_opcodes = 2; break; case E_S32: - if (the_insn.exp.X_add_symbol == NULL && - the_insn.exp.X_op_symbol == NULL && - (the_insn.exp.X_add_number < (1 << 15) && - the_insn.exp.X_add_number >= -(1 << 15))) + if (the_insn.fi[0].exp.X_add_symbol == NULL + && the_insn.fi[0].exp.X_op_symbol == NULL + && (the_insn.fi[0].exp.X_add_number < (1 << 15) + && the_insn.fi[0].exp.X_add_number >= -(1 << 15))) break; - /* orh h%const,r0,r31 */ + + /* Emit "orh h%const,r0,r31". */ pseudo[0].opcode = 0xec000000 | (atmp << 16); - pseudo[0].highlow = HIGH; - /* or l%const,r31,r31 */ + pseudo[0].fi[0].fup = (OP_IMM_S16 | OP_SEL_H); + + /* Emit "or l%const,r31,r31". */ pseudo[1].opcode = 0xe4000000 | (atmp << 21) | (atmp << 16); - pseudo[1].highlow = PAIR; - /* r31,ireg_src2,ireg_dest */ + pseudo[1].fi[0].fup = (OP_IMM_S16 | OP_SEL_L); + + /* Emit "r31,ireg_src2,ireg_dest". */ pseudo[2].opcode = (the_insn.opcode & ~0x0400ffff) | (atmp << 11); - pseudo[2].reloc = NO_RELOC; - no_opcodes = 3; + pseudo[2].fi[0].fup = OP_IMM_S16; + + num_opcodes = 3; break; default: @@ -336,61 +393,87 @@ md_assemble (str) } the_insn = pseudo[0]; - /* check for expanded opcode after branch or in dual */ - if (no_opcodes > 1 && last_expand == 1) + + /* Warn if an opcode is expanded after a delayed branch. */ + if (num_opcodes > 1 && last_expand == 1) as_warn (_("Expanded opcode after delayed branch: `%s'"), str); - if (no_opcodes > 1 && dual_mode != DUAL_OFF) + + /* Warn if an opcode is expanded in dual mode. */ + if (num_opcodes > 1 && dual_mode != DUAL_OFF) as_warn (_("Expanded opcode in dual mode: `%s'"), str); + + /* Notify if any expansions happen. */ + if (target_warn_expand && num_opcodes > 1) + as_warn (_("An instruction was expanded (%s)"), str); } + dwarf2_emit_insn (0); i = 0; do - { /* always produce at least one opcode */ - toP = frag_more (4); - /* put out the opcode */ - md_number_to_chars (toP, the_insn.opcode, 4); - - /* check for expanded opcode after branch or in dual */ - last_expand = the_insn.pcrel; - - /* put out the symbol-dependent stuff */ - if (the_insn.reloc != NO_RELOC) - { - fix_new (frag_now, /* which frag */ - (toP - frag_now->fr_literal), /* where */ - 4, /* size */ - &the_insn.exp, - the_insn.pcrel, - /* merge bit fields into one argument */ - (int) (((the_insn.highlow & 0x3) << 4) | (the_insn.reloc & 0xf))); - } + { + int tmp; + + /* Output the opcode. Note that the i860 always reads instructions + as little-endian data. */ + destp = frag_more (4); + number_to_chars_littleendian (destp, the_insn.opcode, 4); + + /* Check for expanded opcode after branch or in dual mode. */ + last_expand = the_insn.fi[0].pcrel; + + /* Output the symbol-dependent stuff. Only btne and bte will ever + loop more than once here, since only they (possibly) have more + than one fixup. */ + for (tmp = 0; tmp < fc; tmp++) + { + if (the_insn.fi[tmp].fup != OP_NONE) + { + fixS *fix; + fix = fix_new_exp (frag_now, + destp - frag_now->fr_literal, + 4, + &the_insn.fi[tmp].exp, + the_insn.fi[tmp].pcrel, + the_insn.fi[tmp].reloc); + + /* Despite the odd name, this is a scratch field. We use + it to encode operand type information. */ + fix->fx_addnumber = the_insn.fi[tmp].fup; + } + } the_insn = pseudo[++i]; } - while (--no_opcodes > 0); + while (--num_opcodes > 0); } +/* Assemble the instruction pointed to by STR. */ static void -i860_ip (str) - char *str; +i860_process_insn (char *str) { char *s; const char *args; char c; - unsigned long i; struct i860_opcode *insn; - char *argsStart; + char *args_start; unsigned long opcode; unsigned int mask; int match = 0; int comma = 0; +#if 1 /* For compiler warnings. */ + args = 0; + insn = 0; + args_start = 0; + opcode = 0; +#endif - for (s = str; islower (*s) || *s == '.' || *s == '3'; ++s) + for (s = str; ISLOWER (*s) || *s == '.' || *s == '3' + || *s == '2' || *s == '1'; ++s) ; + switch (*s) { - case '\0': break; @@ -407,8 +490,9 @@ i860_ip (str) as_fatal (_("Unknown opcode: `%s'"), str); } + /* Check for dual mode ("d.") opcode prefix. */ if (strncmp (str, "d.", 2) == 0) - { /* check for d. opcode prefix */ + { if (dual_mode == DUAL_ON) dual_mode = DUAL_ONDDOT; else @@ -423,35 +507,42 @@ i860_ip (str) as_bad (_("Unknown opcode: `%s'"), str); return; } + if (comma) - { - *--s = ','; - } - argsStart = s; + *--s = ','; + + args_start = s; for (;;) { + int t; opcode = insn->match; memset (&the_insn, '\0', sizeof (the_insn)); - the_insn.reloc = NO_RELOC; - - /* - * Build the opcode, checking as we go to make - * sure that the operands match - */ - for (args = insn->args;; ++args) + fc = 0; + for (t = 0; t < MAX_FIXUPS; t++) + { + the_insn.fi[t].reloc = BFD_RELOC_NONE; + the_insn.fi[t].pcrel = 0; + the_insn.fi[t].fup = OP_NONE; + } + + /* Build the opcode, checking as we go that the operands match. */ + for (args = insn->args; ; ++args) { + if (fc > MAX_FIXUPS) + abort (); + switch (*args) { - case '\0': /* end of args */ + /* End of args. */ + case '\0': if (*s == '\0') - { - match = 1; - } + match = 1; break; + /* These must match exactly. */ case '+': - case '(': /* these must match exactly */ + case '(': case ')': case ',': case ' ': @@ -459,24 +550,30 @@ i860_ip (str) continue; break; - case '#': /* must be at least one digit */ - if (isdigit (*s++)) + /* Must be at least one digit. */ + case '#': + if (ISDIGIT (*s++)) { - while (isdigit (*s)) - { - ++s; - } + while (ISDIGIT (*s)) + ++s; continue; } break; - case '1': /* next operand must be a register */ + /* Next operand must be a register. */ + case '1': case '2': case 'd': + /* Check for register prefix if necessary. */ + if (reg_prefix && *s != reg_prefix) + goto error; + else if (reg_prefix) + s++; + switch (*s) { - - case 'f': /* frame pointer */ + /* Frame pointer. */ + case 'f': s++; if (*s++ == 'p') { @@ -485,7 +582,8 @@ i860_ip (str) } goto error; - case 's': /* stack pointer */ + /* Stack pointer. */ + case 's': s++; if (*s++ == 'p') { @@ -494,36 +592,31 @@ i860_ip (str) } goto error; - case 'r': /* any register */ + /* Any register r0..r31. */ + case 'r': s++; - if (!isdigit (c = *s++)) + if (!ISDIGIT (c = *s++)) { goto error; } - if (isdigit (*s)) + if (ISDIGIT (*s)) { if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) - { - goto error; - } + goto error; } else - { - c -= '0'; - } + c -= '0'; mask = c; break; - default: /* not this opcode */ + /* Not this opcode. */ + default: goto error; } - /* - * Got the register, now figure out where - * it goes in the opcode. - */ + + /* Obtained the register, now place it in the opcode. */ switch (*args) { - case '1': opcode |= mask << 11; continue; @@ -539,13 +632,20 @@ i860_ip (str) } break; - case 'e': /* next operand is a floating point register */ + /* Next operand is a floating point register. */ + case 'e': case 'f': case 'g': - if (*s++ == 'f' && isdigit (*s)) + /* Check for register prefix if necessary. */ + if (reg_prefix && *s != reg_prefix) + goto error; + else if (reg_prefix) + s++; + + if (*s++ == 'f' && ISDIGIT (*s)) { mask = *s++; - if (isdigit (*s)) + if (ISDIGIT (*s)) { mask = 10 * (mask - '0') + (*s++ - '0'); if (mask >= 32) @@ -554,9 +654,8 @@ i860_ip (str) } } else - { - mask -= '0'; - } + mask -= '0'; + switch (*args) { @@ -570,20 +669,22 @@ i860_ip (str) case 'g': opcode |= mask << 16; - if (dual_mode != DUAL_OFF) - opcode |= (1 << 9); /* dual mode instruction */ - if (dual_mode == DUAL_DDOT) - dual_mode = DUAL_OFF; - if (dual_mode == DUAL_ONDDOT) - dual_mode = DUAL_ON; - if ((opcode & (1 << 10)) && (mask == ((opcode >> 11) & 0x1f))) - as_warn (_("Fsr1 equals fdest with Pipelining")); + if ((opcode & (1 << 10)) && mask != 0 + && (mask == ((opcode >> 11) & 0x1f))) + as_warn (_("Pipelined instruction: fsrc1 = fdest")); continue; } } break; - case 'c': /* next operand must be a control register */ + /* Next operand must be a control register. */ + case 'c': + /* Check for register prefix if necessary. */ + if (reg_prefix && *s != reg_prefix) + goto error; + else if (reg_prefix) + s++; + if (strncmp (s, "fir", 3) == 0) { opcode |= 0x0 << 21; @@ -620,87 +721,216 @@ i860_ip (str) s += 4; continue; } + /* The remaining control registers are XP only. */ + if (target_xp && strncmp (s, "bear", 4) == 0) + { + opcode |= 0x6 << 21; + s += 4; + continue; + } + if (target_xp && strncmp (s, "ccr", 3) == 0) + { + opcode |= 0x7 << 21; + s += 3; + continue; + } + if (target_xp && strncmp (s, "p0", 2) == 0) + { + opcode |= 0x8 << 21; + s += 2; + continue; + } + if (target_xp && strncmp (s, "p1", 2) == 0) + { + opcode |= 0x9 << 21; + s += 2; + continue; + } + if (target_xp && strncmp (s, "p2", 2) == 0) + { + opcode |= 0xa << 21; + s += 2; + continue; + } + if (target_xp && strncmp (s, "p3", 2) == 0) + { + opcode |= 0xb << 21; + s += 2; + continue; + } break; - case '5': /* 5 bit immediate in src1 */ - memset (&the_insn, '\0', sizeof (the_insn)); - if (!getExpression (s)) + /* 5-bit immediate in src1. */ + case '5': + if (! i860_get_expression (s)) { s = expr_end; - if (the_insn.exp.X_add_number & ~0x1f) - as_bad (_("5-bit immediate too large")); - opcode |= (the_insn.exp.X_add_number & 0x1f) << 11; - memset (&the_insn, '\0', sizeof (the_insn)); - the_insn.reloc = NO_RELOC; + the_insn.fi[fc].fup |= OP_IMM_U5; + fc++; continue; } break; - case 'l': /* 26 bit immediate, relative branch */ - the_insn.reloc = BRADDR; - the_insn.pcrel = 1; + /* 26-bit immediate, relative branch (lbroff). */ + case 'l': + the_insn.fi[fc].pcrel = 1; + the_insn.fi[fc].fup |= OP_IMM_BR26; goto immediate; - case 's': /* 16 bit immediate, split relative branch */ - /* upper 5 bits of offset in dest field */ - the_insn.pcrel = 1; - the_insn.reloc = SPLIT0; + /* 16-bit split immediate, relative branch (sbroff). */ + case 'r': + the_insn.fi[fc].pcrel = 1; + the_insn.fi[fc].fup |= OP_IMM_BR16; goto immediate; - case 'S': /* 16 bit immediate, split (st), aligned */ - if (opcode & (1 << 28)) - if (opcode & 0x1) - the_insn.reloc = SPLIT2; - else - the_insn.reloc = SPLIT1; - else - the_insn.reloc = SPLIT0; + /* 16-bit split immediate. */ + case 's': + the_insn.fi[fc].fup |= OP_IMM_SPLIT16; + goto immediate; + + /* 16-bit split immediate, byte aligned (st.b). */ + case 'S': + the_insn.fi[fc].fup |= OP_IMM_SPLIT16; + goto immediate; + + /* 16-bit split immediate, half-word aligned (st.s). */ + case 'T': + the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN2); + goto immediate; + + /* 16-bit split immediate, word aligned (st.l). */ + case 'U': + the_insn.fi[fc].fup |= (OP_IMM_SPLIT16 | OP_ENCODE1 | OP_ALIGN4); + goto immediate; + + /* 16-bit immediate. */ + case 'i': + the_insn.fi[fc].fup |= OP_IMM_S16; + goto immediate; + + /* 16-bit immediate, byte aligned (ld.b). */ + case 'I': + the_insn.fi[fc].fup |= OP_IMM_S16; goto immediate; - case 'I': /* 16 bit immediate, aligned */ - if (opcode & (1 << 28)) - if (opcode & 0x1) - the_insn.reloc = LOW2; - else - the_insn.reloc = LOW1; + /* 16-bit immediate, half-word aligned (ld.s). */ + case 'J': + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN2); + goto immediate; + + /* 16-bit immediate, word aligned (ld.l, {p}fld.l, fst.l). */ + case 'K': + if (insn->name[0] == 'l') + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE1 | OP_ALIGN4); else - the_insn.reloc = LOW0; + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE2 | OP_ALIGN4); goto immediate; - case 'i': /* 16 bit immediate */ - the_insn.reloc = LOW0; + /* 16-bit immediate, double-word aligned ({p}fld.d, fst.d). */ + case 'L': + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN8); + goto immediate; + + /* 16-bit immediate, quad-word aligned (fld.q, fst.q). */ + case 'M': + the_insn.fi[fc].fup |= (OP_IMM_S16 | OP_ENCODE3 | OP_ALIGN16); /*FALLTHROUGH*/ + /* Handle the immediate for either the Intel syntax or + SVR4 syntax. The Intel syntax is "ha%immediate" + whereas SVR4 syntax is "[immediate]@ha". */ immediate: - if (*s == ' ') - s++; - if (strncmp (s, "ha%", 3) == 0) - { - the_insn.highlow = HIGHADJ; - s += 3; - } - else if (strncmp (s, "h%", 2) == 0) + if (target_intel_syntax == 0) { - the_insn.highlow = HIGH; - s += 2; - } - else if (strncmp (s, "l%", 2) == 0) - { - the_insn.highlow = PAIR; - s += 2; - } - the_insn.expand = insn->expand; + /* AT&T/SVR4 syntax. */ + if (*s == ' ') + s++; + + /* Note that if i860_get_expression() fails, we will still + have created U entries in the symbol table for the + 'symbols' in the input string. Try not to create U + symbols for registers, etc. */ + if (! i860_get_expression (s)) + s = expr_end; + else + goto error; + + if (strncmp (s, "@ha", 3) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_HA; + s += 3; + } + else if (strncmp (s, "@h", 2) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_H; + s += 2; + } + else if (strncmp (s, "@l", 2) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_L; + s += 2; + } + else if (strncmp (s, "@gotoff", 7) == 0 + || strncmp (s, "@GOTOFF", 7) == 0) + { + as_bad (_("Assembler does not yet support PIC")); + the_insn.fi[fc].fup |= OP_SEL_GOTOFF; + s += 7; + } + else if (strncmp (s, "@got", 4) == 0 + || strncmp (s, "@GOT", 4) == 0) + { + as_bad (_("Assembler does not yet support PIC")); + the_insn.fi[fc].fup |= OP_SEL_GOT; + s += 4; + } + else if (strncmp (s, "@plt", 4) == 0 + || strncmp (s, "@PLT", 4) == 0) + { + as_bad (_("Assembler does not yet support PIC")); + the_insn.fi[fc].fup |= OP_SEL_PLT; + s += 4; + } - /* Note that if the getExpression() fails, we will still have - created U entries in the symbol table for the 'symbols' - in the input string. Try not to create U symbols for - registers, etc. */ + the_insn.expand = insn->expand; + fc++; - if (!getExpression (s)) + continue; + } + else { - s = expr_end; - continue; + /* Intel syntax. */ + if (*s == ' ') + s++; + if (strncmp (s, "ha%", 3) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_HA; + s += 3; + } + else if (strncmp (s, "h%", 2) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_H; + s += 2; + } + else if (strncmp (s, "l%", 2) == 0) + { + the_insn.fi[fc].fup |= OP_SEL_L; + s += 2; + } + the_insn.expand = insn->expand; + + /* Note that if i860_get_expression() fails, we will still + have created U entries in the symbol table for the + 'symbols' in the input string. Try not to create U + symbols for registers, etc. */ + if (! i860_get_expression (s)) + s = expr_end; + else + goto error; + + fc++; + continue; } break; @@ -713,35 +943,59 @@ i860_ip (str) if (match == 0) { /* Args don't match. */ - if (&insn[1] - i860_opcodes < NUMOPCODES - && !strcmp (insn->name, insn[1].name)) + if (insn[1].name != NULL + && ! strcmp (insn->name, insn[1].name)) { ++insn; - s = argsStart; + s = args_start; continue; } else { - as_bad (_("Illegal operands")); + as_bad (_("Illegal operands for %s"), insn->name); return; } } break; } + /* Set the dual bit on this instruction if necessary. */ + if (dual_mode != DUAL_OFF) + { + if ((opcode & 0xfc000000) == 0x48000000 || opcode == 0xb0000000) + { + /* The instruction is a flop or a fnop, so set its dual bit + (but check that it is 8-byte aligned). */ + if (((frag_now->fr_address + frag_now_fix_octets ()) & 7) == 0) + opcode |= (1 << 9); + else + as_bad (_("'d.%s' must be 8-byte aligned"), insn->name); + + if (dual_mode == DUAL_DDOT) + dual_mode = DUAL_OFF; + else if (dual_mode == DUAL_ONDDOT) + dual_mode = DUAL_ON; + } + else if (dual_mode == DUAL_DDOT || dual_mode == DUAL_ONDDOT) + as_bad (_("Prefix 'd.' invalid for instruction `%s'"), insn->name); + } + the_insn.opcode = opcode; + + /* Only recognize XP instructions when the user has requested it. */ + if (insn->expand == XP_ONLY && ! target_xp) + as_bad (_("Unknown opcode: `%s'"), insn->name); } static int -getExpression (str) - char *str; +i860_get_expression (char *str) { char *save_in; segT seg; save_in = input_line_pointer; input_line_pointer = str; - seg = expression (&the_insn.exp); + seg = expression (&the_insn.fi[fc].exp); if (seg != absolute_section && seg != undefined_section && ! SEG_NORMAL (seg)) @@ -756,508 +1010,482 @@ getExpression (str) return 0; } - -/* - This is identical to the md_atof in m68k.c. I think this is right, - but I'm not sure. - - Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP . An error message is returned, or NULL on OK. - */ - -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -char * -md_atof (type, litP, sizeP) - char type; - char *litP; - int *sizeP; +const char * +md_atof (int type, char *litP, int *sizeP) { - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - char *atof_ieee (); - - switch (type) - { - - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * sizeof (LITTLENUM_TYPE); - for (wordP = words; prec--;) - { - md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return 0; + return ieee_md_atof (type, litP, sizeP, TRUE); } -/* - * Write out big-endian. - */ +/* Write out in current endian mode. */ void -md_number_to_chars (buf, val, n) - char *buf; - valueT val; - int n; +md_number_to_chars (char *buf, valueT val, int n) { - number_to_chars_bigendian (buf, val, n); + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); + else + number_to_chars_littleendian (buf, val, n); } -void -md_number_to_imm (buf, val, n, fixP) - char *buf; - long val; - int n; - fixS *fixP; +/* This should never be called for i860. */ +int +md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, + segT segtype ATTRIBUTE_UNUSED) { - enum reloc_type reloc = fixP->fx_r_type & 0xf; - enum highlow_type highlow = (fixP->fx_r_type >> 4) & 0x3; + as_fatal (_("relaxation not supported\n")); +} - assert (buf); - assert (n == 4); /* always on i860 */ +#ifdef DEBUG_I860 +static void +print_insn (struct i860_it *insn) +{ + if (insn->error) + fprintf (stderr, "ERROR: %s\n", insn->error); - switch (highlow) - { + fprintf (stderr, "opcode = 0x%08lx\t", insn->opcode); + fprintf (stderr, "expand = 0x%x\t", insn->expand); + fprintf (stderr, "reloc = %s\t\n", + bfd_get_reloc_code_name (insn->reloc)); + fprintf (stderr, "exp = {\n"); + fprintf (stderr, "\t\tX_add_symbol = %s\n", + insn->exp.X_add_symbol ? + (S_GET_NAME (insn->exp.X_add_symbol) ? + S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0"); + fprintf (stderr, "\t\tX_op_symbol = %s\n", + insn->exp.X_op_symbol ? + (S_GET_NAME (insn->exp.X_op_symbol) ? + S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0"); + fprintf (stderr, "\t\tX_add_number = %lx\n", + insn->exp.X_add_number); + fprintf (stderr, "}\n"); +} +#endif /* DEBUG_I860 */ + + +#ifdef OBJ_ELF +const char *md_shortopts = "VQ:"; +#else +const char *md_shortopts = ""; +#endif - case HIGHADJ: /* adjusts the high-order 16-bits */ - if (val & (1 << 15)) - val += (1 << 16); +#define OPTION_EB (OPTION_MD_BASE + 0) +#define OPTION_EL (OPTION_MD_BASE + 1) +#define OPTION_WARN_EXPAND (OPTION_MD_BASE + 2) +#define OPTION_XP (OPTION_MD_BASE + 3) +#define OPTION_INTEL_SYNTAX (OPTION_MD_BASE + 4) - /*FALLTHROUGH*/ +struct option md_longopts[] = { + { "EB", no_argument, NULL, OPTION_EB }, + { "EL", no_argument, NULL, OPTION_EL }, + { "mwarn-expand", no_argument, NULL, OPTION_WARN_EXPAND }, + { "mxp", no_argument, NULL, OPTION_XP }, + { "mintel-syntax",no_argument, NULL, OPTION_INTEL_SYNTAX }, + { NULL, no_argument, NULL, 0 } +}; +size_t md_longopts_size = sizeof (md_longopts); - case HIGH: /* selects the high-order 16-bits */ - val >>= 16; +int +md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED) +{ + switch (c) + { + case OPTION_EB: + target_big_endian = 1; break; - case PAIR: /* selects the low-order 16-bits */ - val = val & 0xffff; + case OPTION_EL: + target_big_endian = 0; break; - default: + case OPTION_WARN_EXPAND: + target_warn_expand = 1; break; - } - switch (reloc) - { + case OPTION_XP: + target_xp = 1; + break; - case BRADDR: /* br,call,bc,bc.t,bnc,bnc.t w/26-bit immediate */ - if (fixP->fx_pcrel != 1) - as_bad (_("26-bit branch w/o pc relative set: 0x%08x"), val); - val >>= 2; /* align pcrel offset, see manual */ - - if (val >= (1 << 25) || val < -(1 << 25)) /* check for overflow */ - as_bad (_("26-bit branch offset overflow: 0x%08x"), val); - buf[0] = (buf[0] & 0xfc) | ((val >> 24) & 0x3); - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; + case OPTION_INTEL_SYNTAX: + target_intel_syntax = 1; break; - case SPLIT2: /* 16 bit immediate, 4-byte aligned */ - if (val & 0x3) - as_bad (_("16-bit immediate 4-byte alignment error: 0x%08x"), val); - val &= ~0x3; /* 4-byte align value */ - /*FALLTHROUGH*/ - case SPLIT1: /* 16 bit immediate, 2-byte aligned */ - if (val & 0x1) - as_bad (_("16-bit immediate 2-byte alignment error: 0x%08x"), val); - val &= ~0x1; /* 2-byte align value */ - /*FALLTHROUGH*/ - case SPLIT0: /* st,bla,bte,btne w/16-bit immediate */ - if (fixP->fx_pcrel == 1) - val >>= 2; /* align pcrel offset, see manual */ - /* check for bounds */ - if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) - as_bad (_("16-bit branch offset overflow: 0x%08x"), val); - buf[1] = (buf[1] & ~0x1f) | ((val >> 11) & 0x1f); - buf[2] = (buf[2] & ~0x7) | ((val >> 8) & 0x7); - buf[3] |= val; /* perserve bottom opcode bits */ +#ifdef OBJ_ELF + /* SVR4 argument compatibility (-V): print version ID. */ + case 'V': + print_version_id (); break; - case LOW4: /* fld,pfld,pst,flush 16-byte aligned */ - if (val & 0xf) - as_bad (_("16-bit immediate 16-byte alignment error: 0x%08x"), val); - val &= ~0xf; /* 16-byte align value */ - /*FALLTHROUGH*/ - case LOW3: /* fld,pfld,pst,flush 8-byte aligned */ - if (val & 0x7) - as_bad (_("16-bit immediate 8-byte alignment error: 0x%08x"), val); - val &= ~0x7; /* 8-byte align value */ - /*FALLTHROUGH*/ - case LOW2: /* 16 bit immediate, 4-byte aligned */ - if (val & 0x3) - as_bad (_("16-bit immediate 4-byte alignment error: 0x%08x"), val); - val &= ~0x3; /* 4-byte align value */ - /*FALLTHROUGH*/ - case LOW1: /* 16 bit immediate, 2-byte aligned */ - if (val & 0x1) - as_bad (_("16-bit immediate 2-byte alignment error: 0x%08x"), val); - val &= ~0x1; /* 2-byte align value */ - /*FALLTHROUGH*/ - case LOW0: /* 16 bit immediate, byte aligned */ - /* check for bounds */ - if (highlow != PAIR && (val >= (1 << 16) || val < -(1 << 15))) - as_bad (_("16-bit immediate overflow: 0x%08x"), val); - buf[2] = val >> 8; - buf[3] |= val; /* perserve bottom opcode bits */ + /* SVR4 argument compatibility (-Qy, -Qn): controls whether + a .comment section should be emitted or not (ignored). */ + case 'Q': break; +#endif - case NO_RELOC: default: - as_bad (_("bad relocation type: 0x%02x"), reloc); - break; + return 0; } -} -/* should never be called for i860 */ -void -md_number_to_disp (buf, val, n) - char *buf; - long val; -{ - as_fatal (_("md_number_to_disp\n")); -} - -/* should never be called for i860 */ -void -md_number_to_field (buf, val, fix) - char *buf; - long val; - void *fix; -{ - as_fatal (_("i860_number_to_field\n")); + return 1; } -/* the bit-field entries in the relocation_info struct plays hell - with the byte-order problems of cross-assembly. So as a hack, - I added this mach. dependent ri twiddler. Ugly, but it gets - you there. -KWK */ -/* on i860: first 4 bytes are normal unsigned long address, next three - bytes are index, most sig. byte first. Byte 7 is broken up with - bit 7 as pcrel, bit 6 as extern, and the lower six bits as - relocation type (highlow 5-4). Next 4 bytes are long addend. */ -/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com */ void -md_ri_to_chars (ri_p, ri) - struct relocation_info *ri_p, ri; +md_show_usage (FILE *stream) { -#if 0 - unsigned char the_bytes[sizeof (*ri_p)]; - - /* this is easy */ - md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address)); - /* now the fun stuff */ - the_bytes[4] = (ri.r_index >> 16) & 0x0ff; - the_bytes[5] = (ri.r_index >> 8) & 0x0ff; - the_bytes[6] = ri.r_index & 0x0ff; - the_bytes[7] = ((ri.r_extern << 7) & 0x80) | (0 & 0x60) | (ri.r_type & 0x1F); - /* Also easy */ - md_number_to_chars (&the_bytes[8], ri.r_addend, sizeof (ri.r_addend)); - /* now put it back where you found it, Junior... */ - memcpy ((char *) ri_p, the_bytes, sizeof (*ri_p)); + fprintf (stream, _("\ + -EL generate code for little endian mode (default)\n\ + -EB generate code for big endian mode\n\ + -mwarn-expand warn if pseudo operations are expanded\n\ + -mxp enable i860XP support (disabled by default)\n\ + -mintel-syntax enable Intel syntax (default to AT&T/SVR4)\n")); +#ifdef OBJ_ELF + /* SVR4 compatibility flags. */ + fprintf (stream, _("\ + -V print assembler version number\n\ + -Qy, -Qn ignored\n")); #endif } -/* should never be called for i860 */ -void -md_convert_frag (headers, seg, fragP) - object_headers *headers; - segT seg; - register fragS *fragP; + +/* We have no need to default values of symbols. */ +symbolS * +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) { - as_fatal (_("i860_convert_frag\n")); + return 0; } -/* should never be called for i860 */ -int -md_estimate_size_before_relax (fragP, segtype) - register fragS *fragP; - segT segtype; +/* The i860 denotes auto-increment with '++'. */ +void +md_operand (expressionS *exp) { - as_fatal (_("i860_estimate_size_before_relax\n")); -} + char *s; -/* for debugging only, must match enum reloc_type */ -static char *Reloc[] = -{ - "NO_RELOC", - "BRADDR", - "LOW0", - "LOW1", - "LOW2", - "LOW3", - "LOW4", - "SPLIT0", - "SPLIT1", - "SPLIT2", - "RELOC_32", -}; -static char *Highlow[] = -{ - "NO_SPEC", - "PAIR", - "HIGH", - "HIGHADJ", -}; -static void -print_insn (insn) - struct i860_it *insn; -{ - if (insn->error) + for (s = input_line_pointer; *s; s++) { - fprintf (stderr, "ERROR: %s\n"); + if (s[0] == '+' && s[1] == '+') + { + input_line_pointer += 2; + exp->X_op = O_register; + break; + } } - fprintf (stderr, "opcode=0x%08x\t", insn->opcode); - fprintf (stderr, "expand=0x%08x\t", insn->expand); - fprintf (stderr, "reloc = %s\t", Reloc[insn->reloc]); - fprintf (stderr, "highlow = %s\n", Highlow[insn->highlow]); - fprintf (stderr, "exp = {\n"); - fprintf (stderr, "\t\tX_add_symbol = %s\n", - insn->exp.X_add_symbol ? - (S_GET_NAME (insn->exp.X_add_symbol) ? - S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0"); - fprintf (stderr, "\t\tX_op_symbol = %s\n", - insn->exp.X_op_symbol ? - (S_GET_NAME (insn->exp.X_op_symbol) ? - S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0"); - fprintf (stderr, "\t\tX_add_number = %d\n", - insn->exp.X_add_number); - fprintf (stderr, "}\n"); } - -CONST char *md_shortopts = ""; -struct option md_longopts[] = { - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); -int -md_parse_option (c, arg) - int c; - char *arg; +/* Round up a section size to the appropriate boundary. */ +valueT +md_section_align (segT segment ATTRIBUTE_UNUSED, + valueT size ATTRIBUTE_UNUSED) { - return 0; + /* Byte alignment is fine. */ + return size; } -void -md_show_usage (stream) - FILE *stream; +/* On the i860, a PC-relative offset is relative to the address of the + offset plus its size. */ +long +md_pcrel_from (fixS *fixP) { + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; } - -#ifdef comment -/* - * I860 relocations are completely different, so it needs - * this machine dependent routine to emit them. - */ -void -emit_machine_reloc (fixP, segment_address_in_file) - register fixS *fixP; - relax_addressT segment_address_in_file; -{ - struct reloc_info_i860 ri; - register symbolS *symbolP; - extern char *next_object_file_charP; - long add_number; - memset ((char *) &ri, '\0', sizeof (ri)); - for (; fixP; fixP = fixP->fx_next) +/* Determine the relocation needed for non PC-relative 16-bit immediates. + Also adjust the given immediate as necessary. Finally, check that + all constraints (such as alignment) are satisfied. */ +static bfd_reloc_code_real_type +obtain_reloc_for_imm16 (fixS *fix, long *val) +{ + valueT fup = fix->fx_addnumber; + bfd_reloc_code_real_type reloc; + + if (fix->fx_pcrel) + abort (); + + /* Check alignment restrictions. */ + if ((fup & OP_ALIGN2) && (*val & 0x1)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 2 alignment")); + else if ((fup & OP_ALIGN4) && (*val & 0x3)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 4 alignment")); + else if ((fup & OP_ALIGN8) && (*val & 0x7)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 8 alignment")); + else if ((fup & OP_ALIGN16) && (*val & 0xf)) + as_bad_where (fix->fx_file, fix->fx_line, + _("This immediate requires 0 MOD 16 alignment")); + + if (fup & OP_SEL_HA) { - - if (fixP->fx_r_type & ~0x3f) - { - as_fatal ("fixP->fx_r_type = %d\n", fixP->fx_r_type); - } - ri.r_pcrel = fixP->fx_pcrel; - ri.r_type = fixP->fx_r_type; - - if ((symbolP = fixP->fx_addsy) != NULL) + *val = (*val >> 16) + (*val & 0x8000 ? 1 : 0); + reloc = BFD_RELOC_860_HIGHADJ; + } + else if (fup & OP_SEL_H) + { + *val >>= 16; + reloc = BFD_RELOC_860_HIGH; + } + else if (fup & OP_SEL_L) + { + int num_encode; + if (fup & OP_IMM_SPLIT16) { - ri.r_address = fixP->fx_frag->fr_address + - fixP->fx_where - segment_address_in_file; - if (!S_IS_DEFINED (symbolP)) + if (fup & OP_ENCODE1) { - ri.r_extern = 1; - ri.r_symbolnum = symbolP->sy_number; + num_encode = 1; + reloc = BFD_RELOC_860_SPLIT1; + } + else if (fup & OP_ENCODE2) + { + num_encode = 2; + reloc = BFD_RELOC_860_SPLIT2; } else { - ri.r_extern = 0; - ri.r_symbolnum = S_GET_TYPE (symbolP); + num_encode = 0; + reloc = BFD_RELOC_860_SPLIT0; } - if (symbolP && symbolP->sy_frag) + } + else + { + if (fup & OP_ENCODE1) { - ri.r_addend = symbolP->sy_frag->fr_address; + num_encode = 1; + reloc = BFD_RELOC_860_LOW1; } - ri.r_type = fixP->fx_r_type; - if (fixP->fx_pcrel) + else if (fup & OP_ENCODE2) { - /* preserve actual offset vs. pc + 4 */ - ri.r_addend -= (ri.r_address + 4); + num_encode = 2; + reloc = BFD_RELOC_860_LOW2; + } + else if (fup & OP_ENCODE3) + { + num_encode = 3; + reloc = BFD_RELOC_860_LOW3; } else { - ri.r_addend = fixP->fx_addnumber; + num_encode = 0; + reloc = BFD_RELOC_860_LOW0; } - - md_ri_to_chars ((char *) &ri, ri); - append (&next_object_file_charP, (char *) &ri, sizeof (ri)); } - } -} -#endif /* comment */ + /* Preserve size encode bits. */ + *val &= ~((1 << num_encode) - 1); + } + else + { + /* No selector. What reloc do we generate (???)? */ + reloc = BFD_RELOC_32; + } -#ifdef OBJ_AOUT + return reloc; +} -/* on i860: first 4 bytes are normal unsigned long address, next three - bytes are index, most sig. byte first. Byte 7 is broken up with - bit 7 as pcrel, bit 6 as extern, and the lower six bits as - relocation type (highlow 5-4). Next 4 bytes are long addend. */ +/* Attempt to simplify or eliminate a fixup. To indicate that a fixup + has been eliminated, set fix->fx_done. If fix->fx_addsy is non-NULL, + we will have to generate a reloc entry. */ void -tc_aout_fix_to_chars (where, fixP, segment_address_in_file) - char *where; - fixS *fixP; - relax_addressT segment_address_in_file; +md_apply_fix (fixS *fix, valueT *valP, segT seg ATTRIBUTE_UNUSED) { - long r_index; - long r_extern; - long r_addend = 0; - long r_address; + char *buf; + long val = *valP; + unsigned long insn; + valueT fup; + + buf = fix->fx_frag->fr_literal + fix->fx_where; + + /* Recall that earlier we stored the opcode little-endian. */ + insn = bfd_getl32 (buf); - know (fixP->fx_addsy); - know (!(fixP->fx_r_type & ~0x3f)); + /* We stored a fix-up in this oddly-named scratch field. */ + fup = fix->fx_addnumber; - if (!S_IS_DEFINED (fixP->fx_addsy)) + /* Determine the necessary relocations as well as inserting an + immediate into the instruction. */ + if (fup & OP_IMM_U5) { - r_extern = 1; - r_index = fixP->fx_addsy->sy_number; + if (val & ~0x1f) + as_bad_where (fix->fx_file, fix->fx_line, + _("5-bit immediate too large")); + if (fix->fx_addsy) + as_bad_where (fix->fx_file, fix->fx_line, + _("5-bit field must be absolute")); + + insn |= (val & 0x1f) << 11; + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; } - else + else if (fup & OP_IMM_S16) { - r_extern = 0; - r_index = S_GET_TYPE (fixP->fx_addsy); - } + fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val); - md_number_to_chars (where, - r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, - 4); + /* Insert the immediate. */ + if (fix->fx_addsy) + fix->fx_done = 0; + else + { + insn |= val & 0xffff; + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup & OP_IMM_U16) + abort (); - where[4] = (r_index >> 16) & 0x0ff; - where[5] = (r_index >> 8) & 0x0ff; - where[6] = r_index & 0x0ff; - where[7] = (((fixP->fx_pcrel << 7) & 0x80) - | ((r_extern << 6) & 0x40) - | (fixP->fx_r_type & 0x3F)); + else if (fup & OP_IMM_SPLIT16) + { + fix->fx_r_type = obtain_reloc_for_imm16 (fix, &val); - if (fixP->fx_addsy->sy_frag) + /* Insert the immediate. */ + if (fix->fx_addsy) + fix->fx_done = 0; + else + { + insn |= val & 0x7ff; + insn |= (val & 0xf800) << 5; + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup & OP_IMM_BR16) { - r_addend = fixP->fx_addsy->sy_frag->fr_address; + if (val & 0x3) + as_bad_where (fix->fx_file, fix->fx_line, + _("A branch offset requires 0 MOD 4 alignment")); + + val = val >> 2; + + /* Insert the immediate. */ + if (fix->fx_addsy) + { + fix->fx_done = 0; + fix->fx_r_type = BFD_RELOC_860_PC16; + } + else + { + insn |= (val & 0x7ff); + insn |= ((val & 0xf800) << 5); + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } } + else if (fup & OP_IMM_BR26) + { + if (val & 0x3) + as_bad_where (fix->fx_file, fix->fx_line, + _("A branch offset requires 0 MOD 4 alignment")); + + val >>= 2; - if (fixP->fx_pcrel) + /* Insert the immediate. */ + if (fix->fx_addsy) + { + fix->fx_r_type = BFD_RELOC_860_PC26; + fix->fx_done = 0; + } + else + { + insn |= (val & 0x3ffffff); + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } + } + else if (fup != OP_NONE) { - /* preserve actual offset vs. pc + 4 */ - r_addend -= (r_address + 4); + as_bad_where (fix->fx_file, fix->fx_line, + _("Unrecognized fix-up (0x%08lx)"), (unsigned long) fup); + abort (); } else { - r_addend = fixP->fx_addnumber; + /* I believe only fix-ups such as ".long .ep.main-main+0xc8000000" + reach here (???). */ + if (fix->fx_addsy) + { + fix->fx_r_type = BFD_RELOC_32; + fix->fx_done = 0; + } + else + { + insn |= (val & 0xffffffff); + bfd_putl32 (insn, buf); + fix->fx_r_type = BFD_RELOC_NONE; + fix->fx_done = 1; + } } - - md_number_to_chars (&where[8], r_addend, 4); } -#endif /* OBJ_AOUT */ - -/* We have no need to default values of symbols. */ - -/* ARGSUSED */ -symbolS * -md_undefined_symbol (name) - char *name; +/* Generate a machine dependent reloc from a fixup. */ +arelent* +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, + fixS *fixp) { - return 0; -} + arelent *reloc; -/* Round up a section size to the appropriate boundary. */ -valueT -md_section_align (segment, size) - segT segment; - valueT size; -{ - return size; /* Byte alignment is fine */ -} + reloc = XNEW (arelent); + reloc->sym_ptr_ptr = XNEW (asymbol *); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend = fixp->fx_offset; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); -/* Exactly what point is a PC-relative offset relative TO? - On the i860, they're relative to the address of the offset, plus - its size. (??? Is this right? FIXME-SOON!) */ -long -md_pcrel_from (fixP) - fixS *fixP; -{ - return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; + if (! reloc->howto) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + "Cannot represent %s relocation in object file", + bfd_get_reloc_code_name (fixp->fx_r_type)); + } + return reloc; } +/* This is called from HANDLE_ALIGN in write.c. Fill in the contents + of an rs_align_code fragment. */ + void -md_apply_fix (fixP, val) - fixS *fixP; - long val; +i860_handle_align (fragS *fragp) { - char *place = fixP->fx_where + fixP->fx_frag->fr_literal; + /* Instructions are always stored little-endian on the i860. */ + static const unsigned char le_nop[] = { 0x00, 0x00, 0x00, 0xA0 }; - /* looks to me like i860 never has bit fixes. Let's see. xoxorich. */ - know (fixP->fx_bit_fixP == NULL); - if (!fixP->fx_bit_fixP) - { - fixP->fx_addnumber = val; - md_number_to_imm (place, val, fixP->fx_size, fixP); - } - else + int bytes; + char *p; + + if (fragp->fr_type != rs_align_code) + return; + + bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; + p = fragp->fr_literal + fragp->fr_fix; + + /* Make sure we are on a 4-byte boundary, in case someone has been + putting data into a text section. */ + if (bytes & 3) { - md_number_to_field (place, val, fixP->fx_bit_fixP); + int fix = bytes & 3; + memset (p, 0, fix); + p += fix; + fragp->fr_fix += fix; } + + memcpy (p, le_nop, 4); + fragp->fr_var = 4; } -/* - * Local Variables: - * fill-column: 131 - * comment-column: 0 - * End: - */ +/* This is called after a user-defined label is seen. We check + if the label has a double colon (valid in Intel syntax mode only), + in which case it should be externalized. */ -/* end of tc-i860.c */ +void +i860_check_label (symbolS *labelsym) +{ + /* At this point, the current line pointer is sitting on the character + just after the first colon on the label. */ + if (target_intel_syntax && *input_line_pointer == ':') + { + S_SET_EXTERNAL (labelsym); + input_line_pointer++; + } +}