mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-09-10 23:57:03 +08:00
* config/tc-arc.c (delay_slot_type): New function.
(md_assemble): Use hashed list of insns. Print warning if 8 byte insn appears in delay slot. (md_operand): Handle %st(sym1-sym2). (get_arc_exp_reloc_type): Likewise. (md_apply_fix, case BFD_RELOC_ARC_B26): Now using implicit addends so must store them here.
This commit is contained in:
@ -31,6 +31,7 @@ static arc_insn arc_insert_operand PARAMS ((arc_insn,
|
|||||||
const struct arc_operand *, int,
|
const struct arc_operand *, int,
|
||||||
const struct arc_operand_value *,
|
const struct arc_operand_value *,
|
||||||
offsetT, char *, unsigned int));
|
offsetT, char *, unsigned int));
|
||||||
|
static int delay_slot_type PARAMS ((arc_insn));
|
||||||
static void arc_common PARAMS ((int));
|
static void arc_common PARAMS ((int));
|
||||||
static void arc_cpu PARAMS ((int));
|
static void arc_cpu PARAMS ((int));
|
||||||
/*static void arc_rename PARAMS ((int));*/
|
/*static void arc_rename PARAMS ((int));*/
|
||||||
@ -277,6 +278,18 @@ arc_insert_operand (insn, operand, mods, reg, val, file, line)
|
|||||||
return insn;
|
return insn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the delay slot type for INSN (or -1 if it isn't a branch). */
|
||||||
|
/* ??? This is a quick hack. May wish to later generalize this concept
|
||||||
|
to record all suffixes the insn contains (for various warnings, etc.). */
|
||||||
|
|
||||||
|
static int
|
||||||
|
delay_slot_type (arc_insn insn)
|
||||||
|
{
|
||||||
|
if ((insn >> 27) >= 4 && (insn >> 27) <= 7)
|
||||||
|
return (insn & 0x60) >> 5;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* We need to keep a list of fixups. We can't simply generate them as
|
/* We need to keep a list of fixups. We can't simply generate them as
|
||||||
we go, because that would require us to first create the frag, and
|
we go, because that would require us to first create the frag, and
|
||||||
that would screw up references to ``.''. */
|
that would screw up references to ``.''. */
|
||||||
@ -296,7 +309,7 @@ void
|
|||||||
md_assemble (str)
|
md_assemble (str)
|
||||||
char *str;
|
char *str;
|
||||||
{
|
{
|
||||||
const struct arc_opcode *opcode,*opcode_end;
|
const struct arc_opcode *opcode;
|
||||||
char *start;
|
char *start;
|
||||||
arc_insn insn;
|
arc_insn insn;
|
||||||
static int init_tables_p = 0;
|
static int init_tables_p = 0;
|
||||||
@ -313,23 +326,15 @@ md_assemble (str)
|
|||||||
while (isspace (*str))
|
while (isspace (*str))
|
||||||
str++;
|
str++;
|
||||||
|
|
||||||
/* The instructions are sorted by the first letter. Scan the opcode table
|
/* The instructions are stored in lists hashed by the first letter (though
|
||||||
until we find the right one. */
|
we needn't care how they're hashed). Get the first in the list. */
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep looking until we find a match. If we haven't found a match, and the
|
opcode = arc_opcode_asm_list (str);
|
||||||
first character no longer matches, we needn't look any further. */
|
|
||||||
|
/* Keep looking until we find a match. */
|
||||||
|
|
||||||
start = str;
|
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;
|
||||||
char *syn;
|
char *syn;
|
||||||
@ -604,11 +609,12 @@ md_assemble (str)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *f;
|
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
|
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))
|
while (isspace (*str))
|
||||||
++str;
|
++str;
|
||||||
@ -616,11 +622,28 @@ md_assemble (str)
|
|||||||
if (*str != '\0')
|
if (*str != '\0')
|
||||||
as_bad ("junk at end of line: `%s'", str);
|
as_bad ("junk at end of line: `%s'", str);
|
||||||
|
|
||||||
|
/* Is there a limm value? */
|
||||||
|
limm_p = arc_opcode_limm_p (&limm);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
{
|
||||||
|
static int in_delay_slot_p = 0;
|
||||||
|
int this_insn_delay_slot_type = delay_slot_type (insn);
|
||||||
|
|
||||||
|
if (in_delay_slot_p && limm_p)
|
||||||
|
as_warn ("8 byte instruction in delay slot");
|
||||||
|
if (this_insn_delay_slot_type > 0 && limm_p)
|
||||||
|
as_warn ("8 byte jump instruction with delay slot");
|
||||||
|
in_delay_slot_p = (this_insn_delay_slot_type > 0) && !limm_p;
|
||||||
|
}
|
||||||
|
|
||||||
/* Write out the instruction.
|
/* Write out the instruction.
|
||||||
It is important to fetch enough space in one call to `frag_more'.
|
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
|
We use (f - frag_now->fr_literal) to compute where we are and we
|
||||||
don't want frag_now to change between calls. */
|
don't want frag_now to change between calls. */
|
||||||
if (arc_opcode_limm_p (&limm))
|
if (limm_p)
|
||||||
{
|
{
|
||||||
f = frag_more (8);
|
f = frag_more (8);
|
||||||
md_number_to_chars (f, insn, 4);
|
md_number_to_chars (f, insn, 4);
|
||||||
@ -1036,8 +1059,6 @@ md_operand (expressionP)
|
|||||||
|
|
||||||
if (*p == '%' && strncmp (p, "%st(", 4) == 0)
|
if (*p == '%' && strncmp (p, "%st(", 4) == 0)
|
||||||
{
|
{
|
||||||
expressionS two;
|
|
||||||
|
|
||||||
input_line_pointer += 4;
|
input_line_pointer += 4;
|
||||||
expression (expressionP);
|
expression (expressionP);
|
||||||
if (*input_line_pointer != ')')
|
if (*input_line_pointer != ')')
|
||||||
@ -1046,18 +1067,40 @@ md_operand (expressionP)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++input_line_pointer;
|
++input_line_pointer;
|
||||||
if (expressionP->X_op != O_symbol
|
if (expressionP->X_op == O_symbol
|
||||||
|| expressionP->X_add_number != 0)
|
&& 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;
|
||||||
return;
|
|
||||||
}
|
|
||||||
expressionP->X_op = O_right_shift;
|
expressionP->X_op = O_right_shift;
|
||||||
two.X_op = O_constant;
|
two.X_op = O_constant;
|
||||||
two.X_add_symbol = two.X_op_symbol = NULL;
|
two.X_add_symbol = two.X_op_symbol = NULL;
|
||||||
two.X_add_number = 2;
|
two.X_add_number = 2;
|
||||||
expressionP->X_op_symbol = make_expr_symbol (&two);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have no need to default values of symbols.
|
/* We have no need to default values of symbols.
|
||||||
@ -1160,25 +1203,31 @@ get_arc_exp_reloc_type (data_p, default_type, exp, expnew)
|
|||||||
expressionS *expnew;
|
expressionS *expnew;
|
||||||
{
|
{
|
||||||
/* If the expression is "symbol >> 2" we must change it to just "symbol",
|
/* 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
|
as fix_new_exp can't handle it. Similarily for (symbol - symbol) >> 2.
|
||||||
on here is that we're using ">> 2" as a special syntax for specifying
|
That's ok though. What's really going on here is that we're using
|
||||||
BFD_RELOC_ARC_B26. */
|
">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26. */
|
||||||
|
|
||||||
if (exp->X_op == O_right_shift)
|
if (exp->X_op == O_right_shift
|
||||||
{
|
|
||||||
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 != NULL
|
||||||
&& exp->X_op_symbol->sy_value.X_op == O_constant
|
&& exp->X_op_symbol->sy_value.X_op == O_constant
|
||||||
&& exp->X_op_symbol->sy_value.X_add_number == 2
|
&& exp->X_op_symbol->sy_value.X_add_number == 2
|
||||||
&& exp->X_add_number == 0)
|
&& 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))
|
||||||
{
|
{
|
||||||
*expnew = *exp;
|
*expnew = *exp;
|
||||||
expnew->X_op = O_symbol;
|
expnew->X_op = O_symbol;
|
||||||
expnew->X_op_symbol = NULL;
|
expnew->X_op_symbol = NULL;
|
||||||
return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J'];
|
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;
|
*expnew = *exp;
|
||||||
@ -1314,7 +1363,6 @@ md_apply_fix (fixP, valueP)
|
|||||||
value, 2);
|
value, 2);
|
||||||
break;
|
break;
|
||||||
case BFD_RELOC_32:
|
case BFD_RELOC_32:
|
||||||
case BFD_RELOC_ARC_B26:
|
|
||||||
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
|
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
|
||||||
value, 4);
|
value, 4);
|
||||||
break;
|
break;
|
||||||
@ -1324,6 +1372,15 @@ md_apply_fix (fixP, valueP)
|
|||||||
value, 8);
|
value, 8);
|
||||||
break;
|
break;
|
||||||
#endif
|
#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:
|
default:
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user