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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdio.h>
#include <ctype.h>
{ NULL, 0, 0 },
};
-const int md_short_jump_size = 4;
-const int md_long_jump_size = 4;
-
/* 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[] = "#;";
/* Byte order. */
extern int target_big_endian;
const char *arc_target_format = DEFAULT_TARGET_FORMAT;
-static int byte_order;
+static int byte_order = DEFAULT_BYTE_ORDER;
/* One of bfd_mach_arc_xxx. */
static int arc_mach_type = bfd_mach_arc_base;
expressionS exp;
};
-#define MAX_INSN_FIXUPS 5
+#define MAX_FIXUPS 5
+
+#define MAX_SUFFIXES 5
/* This routine is called for each instruction to be assembled. */
md_assemble (str)
char *str;
{
- const struct arc_opcode *opcode,*opcode_end;
+ const struct arc_opcode *opcode;
char *start;
arc_insn insn;
static int init_tables_p = 0;
while (isspace (*str))
str++;
- /* The instructions are sorted by the first letter. Scan the opcode table
- until we find the right one. */
- opcode_end = arc_opcodes + arc_opcodes_count;
- for (opcode = arc_opcodes; opcode < opcode_end; opcode++)
- if (*opcode->syntax == *str)
- break;
- if (opcode == opcode_end)
- {
- as_bad ("bad instruction `%s'", str);
- return;
- }
+ /* The instructions are stored in lists hashed by the first letter (though
+ we needn't care how they're hashed). Get the first in the list. */
- /* Keep looking until we find a match. If we haven't found a match, and the
- first character no longer matches, we needn't look any further. */
+ opcode = arc_opcode_lookup_asm (str);
+
+ /* Keep looking until we find a match. */
start = str;
- for ( ; opcode < opcode_end && *opcode->syntax == *start; ++opcode)
+ for ( ; opcode != NULL; opcode = ARC_OPCODE_NEXT_ASM (opcode))
{
- int past_opcode_p;
+ int past_opcode_p, fc, num_suffixes;
char *syn;
- struct arc_fixup fixups[MAX_INSN_FIXUPS];
- int fc,limm_reloc_p;
+ struct arc_fixup fixups[MAX_FIXUPS];
+ /* Used as a sanity check. If we need a limm reloc, make sure we ask
+ for an extra 4 bytes from frag_more. */
+ int limm_reloc_p;
+ const struct arc_operand_value *insn_suffixes[MAX_SUFFIXES];
/* Is this opcode supported by the selected cpu? */
if (! arc_opcode_supported (opcode))
insn = opcode->value;
fc = 0;
past_opcode_p = 0;
-
- /* Used as a sanity check. If we need a limm reloc, make sure we ask
- for an extra 4 bytes from frag_more. */
+ num_suffixes = 0;
limm_reloc_p = 0;
/* We don't check for (*str != '\0') here because we want to parse
suffix_end = arc_suffixes + arc_suffixes_count;
for (suffix = suf;
suffix < suffix_end && strcmp (suffix->name, suf->name) == 0;
- suffix++)
+ ++suffix)
{
if (arc_operands[suffix->type].fmt == *syn)
{
}
++syn;
if (!found)
- /* There's nothing to do except go on to try the next one.
- ??? This test can be deleted when we're done. */
- ;
+ ; /* Wrong type. Just go on to try next insn entry. */
+ else
+ {
+ if (num_suffixes == MAX_SUFFIXES)
+ as_bad ("too many suffixes");
+ else
+ insn_suffixes[num_suffixes++] = suffix;
+ }
}
else
/* This is either a register or an expression of some kind. */
else
{
/* We need to generate a fixup for this expression. */
- if (fc >= MAX_INSN_FIXUPS)
+ if (fc >= MAX_FIXUPS)
as_fatal ("too many fixups");
fixups[fc].exp = exp;
}
/* If we're at the end of the syntax string, we're done. */
+ /* FIXME: try to move this to a separate function. */
if (*syn == '\0')
{
int i;
char *f;
- long limm;
+ long limm, limm_p;
- /* ??? For the moment we assume a valid `str' can only contain blanks
+ /* For the moment we assume a valid `str' can only contain blanks
now. IE: We needn't try again with a longer version of the
- insn. */
+ insn and it is assumed that longer versions of insns appear
+ before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
while (isspace (*str))
++str;
if (*str != '\0')
as_bad ("junk at end of line: `%s'", str);
+ /* Is there a limm value? */
+ limm_p = arc_opcode_limm_p (&limm);
+
+ /* Perform various error and warning tests. */
+
+ {
+ static int in_delay_slot_p = 0;
+ static int prev_insn_needs_cc_nop_p = 0;
+ /* delay slot type seen */
+ int delay_slot_type = ARC_DELAY_NONE;
+ /* conditional execution flag seen */
+ int conditional = 0;
+ /* 1 if condition codes are being set */
+ int cc_set_p = 0;
+ /* 1 if conditional branch, including `b' "branch always" */
+ int cond_branch_p = opcode->flags & ARC_OPCODE_COND_BRANCH;
+ int need_cc_nop_p = 0;
+
+ for (i = 0; i < num_suffixes; ++i)
+ {
+ switch (arc_operands[insn_suffixes[i]->type].fmt)
+ {
+ case 'n' :
+ delay_slot_type = insn_suffixes[i]->value;
+ break;
+ case 'q' :
+ conditional = insn_suffixes[i]->value;
+ break;
+ case 'f' :
+ cc_set_p = 1;
+ break;
+ }
+ }
+
+ /* Putting an insn with a limm value in a delay slot is supposed to
+ be legal, but let's warn the user anyway. Ditto for 8 byte
+ jumps with delay slots. */
+ if (in_delay_slot_p && limm_p)
+ as_warn ("8 byte instruction in delay slot");
+ if (delay_slot_type != ARC_DELAY_NONE && limm_p)
+ as_warn ("8 byte jump instruction with delay slot");
+ in_delay_slot_p = (delay_slot_type != ARC_DELAY_NONE) && !limm_p;
+
+ /* Warn when a conditional branch immediately follows a set of
+ the condition codes. Note that this needn't be done if the
+ insn that sets the condition codes uses a limm. */
+ if (cond_branch_p && conditional != 0 /* 0 = "always" */
+ && prev_insn_needs_cc_nop_p)
+ as_warn ("conditional branch follows set of flags");
+ prev_insn_needs_cc_nop_p = cc_set_p && !limm_p;
+ }
+
/* Write out the instruction.
It is important to fetch enough space in one call to `frag_more'.
We use (f - frag_now->fr_literal) to compute where we are and we
don't want frag_now to change between calls. */
- if (arc_opcode_limm_p (&limm))
+ if (limm_p)
{
f = frag_more (8);
md_number_to_chars (f, insn, 4);
abort ();
}
-const relax_typeS md_relax_table[] =
-{
- { 0 }
-};
-
/* Convert a machine dependent frag. We never generate these. */
void
if (*p == '%' && strncmp (p, "%st(", 4) == 0)
{
- expressionS two;
-
input_line_pointer += 4;
expression (expressionP);
if (*input_line_pointer != ')')
return;
}
++input_line_pointer;
- if (expressionP->X_op != O_symbol
- || expressionP->X_add_number != 0)
+ if (expressionP->X_op == O_symbol
+ && expressionP->X_add_number == 0
+ /* I think this test is unnecessary but just as a sanity check... */
+ && expressionP->X_op_symbol == NULL)
{
- as_bad ("expression too complex for %st");
+ expressionS two;
+
+ expressionP->X_op = O_right_shift;
+ two.X_op = O_constant;
+ two.X_add_symbol = two.X_op_symbol = NULL;
+ two.X_add_number = 2;
+ expressionP->X_op_symbol = make_expr_symbol (&two);
+ }
+ /* allow %st(sym1-sym2) */
+ else if (expressionP->X_op == O_subtract
+ && expressionP->X_add_symbol != NULL
+ && expressionP->X_op_symbol != NULL
+ && expressionP->X_add_number == 0)
+ {
+ expressionS two;
+
+ expressionP->X_add_symbol = make_expr_symbol (expressionP);
+ expressionP->X_op = O_right_shift;
+ two.X_op = O_constant;
+ two.X_add_symbol = two.X_op_symbol = NULL;
+ two.X_add_number = 2;
+ expressionP->X_op_symbol = make_expr_symbol (&two);
+ }
+ else
+ {
+ as_bad ("expression too complex for %%st");
return;
}
- expressionP->X_op = O_right_shift;
- two.X_op = O_constant;
- two.X_add_symbol = two.X_op_symbol = NULL;
- two.X_add_number = 2;
- expressionP->X_op_symbol = make_expr_symbol (&two);
}
}
{
if (fixP->fx_addsy != (symbolS *) NULL
&& ! S_IS_DEFINED (fixP->fx_addsy))
- /* Return offset from PC to delay slot. Offsets are from there. */
- return 4;
+ {
+ /* The symbol is undefined. Let the linker figure it out. */
+ return 0;
+ }
/* Return the address of the delay slot. */
return fixP->fx_frag->fr_address + fixP->fx_where + fixP->fx_size;
expressionS *expnew;
{
/* If the expression is "symbol >> 2" we must change it to just "symbol",
- as fix_new_exp can't handle it. That's ok though. What's really going
- on here is that we're using ">> 2" as a special syntax for specifying
- BFD_RELOC_ARC_B26. */
-
- if (exp->X_op == O_right_shift)
+ as fix_new_exp can't handle it. Similarily for (symbol - symbol) >> 2.
+ That's ok though. What's really going on here is that we're using
+ ">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26. */
+
+ if (exp->X_op == O_right_shift
+ && exp->X_op_symbol != NULL
+ && exp->X_op_symbol->sy_value.X_op == O_constant
+ && exp->X_op_symbol->sy_value.X_add_number == 2
+ && exp->X_add_number == 0)
{
if (exp->X_add_symbol != NULL
&& (exp->X_add_symbol->sy_value.X_op == O_constant
- || exp->X_add_symbol->sy_value.X_op == O_symbol)
- && exp->X_op_symbol != NULL
- && exp->X_op_symbol->sy_value.X_op == O_constant
- && exp->X_op_symbol->sy_value.X_add_number == 2
- && exp->X_add_number == 0)
+ || exp->X_add_symbol->sy_value.X_op == O_symbol))
{
*expnew = *exp;
expnew->X_op = O_symbol;
expnew->X_op_symbol = NULL;
return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
}
+ else if (exp->X_add_symbol != NULL
+ && exp->X_add_symbol->sy_value.X_op == O_subtract)
+ {
+ *expnew = exp->X_add_symbol->sy_value;
+ return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
+ }
}
*expnew = *exp;
that, we determine the correct reloc code and put it back in the fixup. */
int
-md_apply_fix (fixP, valueP)
+md_apply_fix3 (fixP, valueP, seg)
fixS *fixP;
valueT *valueP;
+ segT seg;
{
/*char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;*/
valueT value;
fixP->fx_done = 1;
}
else if (fixP->fx_pcrel)
- value = *valueP;
+ {
+ value = *valueP;
+ /* ELF relocations are against symbols.
+ If this symbol is in a different section then we need to leave it for
+ the linker to deal with. Unfortunately, md_pcrel_from can't tell,
+ so we have to undo it's effects here. */
+ if (S_IS_DEFINED (fixP->fx_addsy)
+ && S_GET_SEGMENT (fixP->fx_addsy) != seg)
+ value += md_pcrel_from (fixP);
+ }
else
{
value = fixP->fx_offset;
value, 2);
break;
case BFD_RELOC_32:
- case BFD_RELOC_ARC_B26:
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
value, 4);
break;
value, 8);
break;
#endif
+ case BFD_RELOC_ARC_B26:
+ /* If !fixP->fx_done then `value' is an implicit addend.
+ We must shift it right by 2 in this case as well because the
+ linker performs the relocation and then adds this in (as opposed
+ to adding this in and then shifting right by 2). */
+ value >>= 2;
+ md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+ value, 4);
+ break;
default:
abort ();
}
fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
return NULL;
}
- reloc->addend = fixP->fx_addnumber;
assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+ reloc->addend = fixP->fx_addnumber;
+
return reloc;
}
\f