/* tc-arc.c -- Assembler for the ARC
- Copyright (C) 1994-2020 Free Software Foundation, Inc.
+ Copyright (C) 1994-2021 Free Software Foundation, Inc.
Contributor: Claudiu Zissulescu <claziss@synopsys.com>
static enum mach_selection_type mach_selection_mode = MACH_SELECTION_NONE;
/* The hash table of instruction opcodes. */
-static struct hash_control *arc_opcode_hash;
+static htab_t arc_opcode_hash;
/* The hash table of register symbols. */
-static struct hash_control *arc_reg_hash;
+static htab_t arc_reg_hash;
/* The hash table of aux register symbols. */
-static struct hash_control *arc_aux_hash;
+static htab_t arc_aux_hash;
/* The hash table of address types. */
-static struct hash_control *arc_addrtype_hash;
+static htab_t arc_addrtype_hash;
#define ARC_CPU_TYPE_A6xx(NAME,EXTRA) \
{ #NAME, ARC_OPCODE_ARC600, bfd_mach_arc_arc600, \
{
const struct arc_opcode_hash_entry *entry;
- entry = hash_find (arc_opcode_hash, name);
+ entry = str_hash_find (arc_opcode_hash, name);
return entry;
}
static void
arc_insert_opcode (const struct arc_opcode *opcode)
{
- const char *name, *retval;
+ const char *name;
struct arc_opcode_hash_entry *entry;
name = opcode->name;
- entry = hash_find (arc_opcode_hash, name);
+ entry = str_hash_find (arc_opcode_hash, name);
if (entry == NULL)
{
entry = XNEW (struct arc_opcode_hash_entry);
entry->count = 0;
entry->opcode = NULL;
- retval = hash_insert (arc_opcode_hash, name, (void *) entry);
- if (retval)
- as_fatal (_("internal error: can't hash opcode '%s': %s"),
- name, retval);
+ if (str_hash_insert (arc_opcode_hash, name, entry, 0) != NULL)
+ as_fatal (_("duplicate %s"), name);
}
entry->opcode = XRESIZEVEC (const struct arc_opcode *, entry->opcode,
entry->count + 1);
- if (entry->opcode == NULL)
- as_fatal (_("Virtual memory exhausted"));
-
entry->opcode[entry->count] = opcode;
entry->count++;
}
arc_select_cpu (const char *arg, enum mach_selection_type sel)
{
int i;
+ static struct cpu_type old_cpu = { 0, 0, 0, E_ARC_OSABI_CURRENT, 0 };
/* We should only set a default if we've not made a selection from some
other source. */
}
return;
}
-
/* Initialise static global data about selected machine type. */
selected_cpu.flags = cpu_types[i].flags;
selected_cpu.name = cpu_types[i].name;
/* Check if set features are compatible with the chosen CPU. */
arc_check_feature ();
+ /* If we change the CPU, we need to re-init the bfd. */
+ if (mach_selection_mode != MACH_SELECTION_NONE
+ && (old_cpu.mach != selected_cpu.mach))
+ {
+ bfd_find_target (arc_target_format, stdoutput);
+ if (! bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
+ as_warn (_("Could not set architecture and machine"));
+ }
+
mach_selection_mode = sel;
+ old_cpu = selected_cpu;
}
/* Here ends all the ARCompact extension instruction assembling
fflush (stderr);
}
+/* Helper for parsing an argument, used for sorting out the relocation
+ type. */
+
+static void
+parse_reloc_symbol (expressionS *resultP)
+{
+ char *reloc_name, c, *sym_name;
+ size_t len;
+ int i;
+ const struct arc_reloc_op_tag *r;
+ expressionS right;
+ symbolS *base;
+
+ /* A relocation operand has the following form
+ @identifier@relocation_type. The identifier is already in
+ tok! */
+ if (resultP->X_op != O_symbol)
+ {
+ as_bad (_("No valid label relocation operand"));
+ resultP->X_op = O_illegal;
+ return;
+ }
+
+ /* Parse @relocation_type. */
+ input_line_pointer++;
+ c = get_symbol_name (&reloc_name);
+ len = input_line_pointer - reloc_name;
+ if (len == 0)
+ {
+ as_bad (_("No relocation operand"));
+ resultP->X_op = O_illegal;
+ return;
+ }
+
+ /* Go through known relocation and try to find a match. */
+ r = &arc_reloc_op[0];
+ for (i = arc_num_reloc_op - 1; i >= 0; i--, r++)
+ if (len == r->length
+ && memcmp (reloc_name, r->name, len) == 0)
+ break;
+ if (i < 0)
+ {
+ as_bad (_("Unknown relocation operand: @%s"), reloc_name);
+ resultP->X_op = O_illegal;
+ return;
+ }
+
+ *input_line_pointer = c;
+ SKIP_WHITESPACE_AFTER_NAME ();
+ /* Extra check for TLS: base. */
+ if (*input_line_pointer == '@')
+ {
+ if (resultP->X_op_symbol != NULL
+ || resultP->X_op != O_symbol)
+ {
+ as_bad (_("Unable to parse TLS base: %s"),
+ input_line_pointer);
+ resultP->X_op = O_illegal;
+ return;
+ }
+ input_line_pointer++;
+ c = get_symbol_name (&sym_name);
+ base = symbol_find_or_make (sym_name);
+ resultP->X_op = O_subtract;
+ resultP->X_op_symbol = base;
+ restore_line_pointer (c);
+ right.X_add_number = 0;
+ }
+
+ if ((*input_line_pointer != '+')
+ && (*input_line_pointer != '-'))
+ right.X_add_number = 0;
+ else
+ {
+ /* Parse the constant of a complex relocation expression
+ like @identifier@reloc +/- const. */
+ if (! r->complex_expr)
+ {
+ as_bad (_("@%s is not a complex relocation."), r->name);
+ resultP->X_op = O_illegal;
+ return;
+ }
+ expression (&right);
+ if (right.X_op != O_constant)
+ {
+ as_bad (_("Bad expression: @%s + %s."),
+ r->name, input_line_pointer);
+ resultP->X_op = O_illegal;
+ return;
+ }
+ }
+
+ resultP->X_md = r->op;
+ resultP->X_add_number = right.X_add_number;
+}
+
/* Parse the arguments to an opcode. */
static int
bfd_boolean saw_arg = FALSE;
int brk_lvl = 0;
int num_args = 0;
- int i;
- size_t len;
- const struct arc_reloc_op_tag *r;
- expressionS tmpE;
- char *reloc_name, c;
memset (tok, 0, sizeof (*tok) * ntok);
goto err;
/* Parse @label. */
+ input_line_pointer++;
tok->X_op = O_symbol;
tok->X_md = O_absent;
expression (tok);
- if (*input_line_pointer != '@')
- goto normalsymbol; /* This is not a relocation. */
-
- relocationsym:
-
- /* A relocation operand has the following form
- @identifier@relocation_type. The identifier is already
- in tok! */
- if (tok->X_op != O_symbol)
- {
- as_bad (_("No valid label relocation operand"));
- goto err;
- }
-
- /* Parse @relocation_type. */
- input_line_pointer++;
- c = get_symbol_name (&reloc_name);
- len = input_line_pointer - reloc_name;
- if (len == 0)
- {
- as_bad (_("No relocation operand"));
- goto err;
- }
-
- /* Go through known relocation and try to find a match. */
- r = &arc_reloc_op[0];
- for (i = arc_num_reloc_op - 1; i >= 0; i--, r++)
- if (len == r->length
- && memcmp (reloc_name, r->name, len) == 0)
- break;
- if (i < 0)
- {
- as_bad (_("Unknown relocation operand: @%s"), reloc_name);
- goto err;
- }
- *input_line_pointer = c;
- SKIP_WHITESPACE_AFTER_NAME ();
- /* Extra check for TLS: base. */
if (*input_line_pointer == '@')
- {
- symbolS *base;
- if (tok->X_op_symbol != NULL
- || tok->X_op != O_symbol)
- {
- as_bad (_("Unable to parse TLS base: %s"),
- input_line_pointer);
- goto err;
- }
- input_line_pointer++;
- char *sym_name;
- c = get_symbol_name (&sym_name);
- base = symbol_find_or_make (sym_name);
- tok->X_op = O_subtract;
- tok->X_op_symbol = base;
- restore_line_pointer (c);
- tmpE.X_add_number = 0;
- }
- if ((*input_line_pointer != '+')
- && (*input_line_pointer != '-'))
- {
- tmpE.X_add_number = 0;
- }
- else
- {
- /* Parse the constant of a complex relocation expression
- like @identifier@reloc +/- const. */
- if (! r->complex_expr)
- {
- as_bad (_("@%s is not a complex relocation."), r->name);
- goto err;
- }
- expression (&tmpE);
- if (tmpE.X_op != O_constant)
- {
- as_bad (_("Bad expression: @%s + %s."),
- r->name, input_line_pointer);
- goto err;
- }
- }
-
- tok->X_md = r->op;
- tok->X_add_number = tmpE.X_add_number;
+ parse_reloc_symbol (tok);
debug_exp (tok);
+ if (tok->X_op == O_illegal
+ || tok->X_op == O_absent
+ || num_args == ntok)
+ goto err;
+
saw_comma = FALSE;
saw_arg = TRUE;
tok++;
identifier@relocation_type, if it is the case parse the
relocation type as well. */
if (*input_line_pointer == '@')
- goto relocationsym;
+ parse_reloc_symbol (tok);
- normalsymbol:
debug_exp (tok);
if (tok->X_op == O_illegal
size_t total_len;
pr_debug ("Emit insn : 0x%llx\n", insn->insn);
- pr_debug ("\tLength : 0x%d\n", insn->len);
+ pr_debug ("\tLength : %d\n", insn->len);
pr_debug ("\tLong imm: 0x%lx\n", insn->limm);
/* Write out the instruction. */
int ntok = *pntok;
int got_cpu_match = 0;
expressionS bktok[MAX_INSN_ARGS];
- int bkntok;
+ int bkntok, maxerridx = 0;
expressionS emptyE;
+ const char *tmpmsg = NULL;
arc_opcode_hash_entry_iterator_init (&iter);
memset (&emptyE, 0, sizeof (emptyE));
{
case ARC_OPERAND_ADDRTYPE:
{
- *errmsg = NULL;
+ tmpmsg = NULL;
/* Check to be an address type. */
if (tok[tokidx].X_op != O_addrtype)
address type. */
gas_assert (operand->insert != NULL);
(*operand->insert) (0, tok[tokidx].X_add_number,
- errmsg);
- if (*errmsg != NULL)
+ &tmpmsg);
+ if (tmpmsg != NULL)
goto match_failed;
}
break;
/* Special handling? */
if (operand->insert)
{
- *errmsg = NULL;
+ tmpmsg = NULL;
(*operand->insert)(0,
regno (tok[tokidx].X_add_number),
- errmsg);
- if (*errmsg)
+ &tmpmsg);
+ if (tmpmsg)
{
if (operand->flags & ARC_OPERAND_IGNORE)
{
tmpp = strdup (p);
for (pp = tmpp; *pp; ++pp) *pp = TOLOWER (*pp);
- auxr = hash_find (arc_aux_hash, tmpp);
+ auxr = str_hash_find (arc_aux_hash, tmpp);
if (auxr)
{
/* We modify the token array here, safe in the
}
if (val < min || val > max)
- goto match_failed;
+ {
+ tmpmsg = _("immediate is out of bounds");
+ goto match_failed;
+ }
/* Check alignments. */
if ((operand->flags & ARC_OPERAND_ALIGNED32)
&& (val & 0x03))
- goto match_failed;
+ {
+ tmpmsg = _("immediate is not 32bit aligned");
+ goto match_failed;
+ }
if ((operand->flags & ARC_OPERAND_ALIGNED16)
&& (val & 0x01))
- goto match_failed;
+ {
+ tmpmsg = _("immediate is not 16bit aligned");
+ goto match_failed;
+ }
}
else if (operand->flags & ARC_OPERAND_NCHK)
{
if (operand->insert)
{
- *errmsg = NULL;
+ tmpmsg = NULL;
(*operand->insert)(0,
tok[tokidx].X_add_number,
- errmsg);
- if (*errmsg)
+ &tmpmsg);
+ if (tmpmsg)
goto match_failed;
}
else if (!(operand->flags & ARC_OPERAND_IGNORE))
regs |= get_register (tok[tokidx].X_op_symbol);
if (operand->insert)
{
- *errmsg = NULL;
+ tmpmsg = NULL;
(*operand->insert)(0,
regs,
- errmsg);
- if (*errmsg)
+ &tmpmsg);
+ if (tmpmsg)
goto match_failed;
}
else
|| t->X_op == O_absent
|| t->X_op == O_register
|| (t->X_add_number != tok[tokidx].X_add_number))
- goto match_failed;
+ {
+ tmpmsg = _("operand is not duplicate of the "
+ "previous one");
+ goto match_failed;
+ }
}
t = &tok[tokidx];
break;
/* Setup ready for flag parsing. */
if (!parse_opcode_flags (opcode, nflgs, first_pflag))
- goto match_failed;
+ {
+ tmpmsg = _("flag mismatch");
+ goto match_failed;
+ }
pr_debug ("flg");
/* Possible match -- did we use all of our input? */
pr_debug ("\n");
return opcode;
}
+ tmpmsg = _("too many arguments");
match_failed:;
pr_debug ("\n");
/* Restore the original parameters. */
memcpy (tok, bktok, MAX_INSN_ARGS * sizeof (*tok));
ntok = bkntok;
+ if (tokidx >= maxerridx
+ && tmpmsg)
+ {
+ maxerridx = tokidx;
+ *errmsg = tmpmsg;
+ }
}
if (*pcpumatch)
static void
declare_register (const char *name, int number)
{
- const char *err;
symbolS *regS = symbol_create (name, reg_section,
- number, &zero_address_frag);
+ &zero_address_frag, number);
- err = hash_insert (arc_reg_hash, S_GET_NAME (regS), (void *) regS);
- if (err)
- as_fatal (_("Inserting \"%s\" into register table failed: %s"),
- name, err);
+ if (str_hash_insert (arc_reg_hash, S_GET_NAME (regS), regS, 0) != NULL)
+ as_fatal (_("duplicate %s"), name);
}
/* Construct symbols for each of the general registers. */
int i;
for (i = 0; i < 64; ++i)
{
- char name[7];
+ char name[32];
sprintf (name, "r%d", i);
declare_register (name, i);
static void
declare_addrtype (const char *name, int number)
{
- const char *err;
symbolS *addrtypeS = symbol_create (name, undefined_section,
- number, &zero_address_frag);
+ &zero_address_frag, number);
- err = hash_insert (arc_addrtype_hash, S_GET_NAME (addrtypeS),
- (void *) addrtypeS);
- if (err)
- as_fatal (_("Inserting \"%s\" into address type table failed: %s"),
- name, err);
+ if (str_hash_insert (arc_addrtype_hash, S_GET_NAME (addrtypeS), addrtypeS, 0))
+ as_fatal (_("duplicate %s"), name);
}
/* Port-specific assembler initialization. This function is called
bfd_set_private_flags (stdoutput, selected_cpu.eflags);
/* Set up a hash table for the instructions. */
- arc_opcode_hash = hash_new ();
- if (arc_opcode_hash == NULL)
- as_fatal (_("Virtual memory exhausted"));
+ arc_opcode_hash = str_htab_create ();
/* Initialize the hash table with the insns. */
do
}while (opcode->name);
/* Register declaration. */
- arc_reg_hash = hash_new ();
- if (arc_reg_hash == NULL)
- as_fatal (_("Virtual memory exhausted"));
+ arc_reg_hash = str_htab_create ();
declare_register_set ();
declare_register ("gp", 26);
memset (&arc_last_insns[0], 0, sizeof (arc_last_insns));
/* Aux register declaration. */
- arc_aux_hash = hash_new ();
- if (arc_aux_hash == NULL)
- as_fatal (_("Virtual memory exhausted"));
+ arc_aux_hash = str_htab_create ();
const struct arc_aux_reg *auxr = &arc_aux_regs[0];
unsigned int i;
for (i = 0; i < arc_num_aux_regs; i++, auxr++)
{
- const char *retval;
-
if (!(auxr->cpu & selected_cpu.flags))
continue;
&& !check_cpu_feature (auxr->subclass))
continue;
- retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
- if (retval)
- as_fatal (_("internal error: can't hash aux register '%s': %s"),
- auxr->name, retval);
+ if (str_hash_insert (arc_aux_hash, auxr->name, auxr, 0) != 0)
+ as_fatal (_("duplicate %s"), auxr->name);
}
/* Address type declaration. */
- arc_addrtype_hash = hash_new ();
- if (arc_addrtype_hash == NULL)
- as_fatal (_("Virtual memory exhausted"));
+ arc_addrtype_hash = str_htab_create ();
declare_addrtype ("bd", ARC_NPS400_ADDRTYPE_BD);
declare_addrtype ("jid", ARC_NPS400_ADDRTYPE_JID);
as_bad ("GOT already in symbol table");
GOT_symbol = symbol_new (GLOBAL_OFFSET_TABLE_NAME, undefined_section,
- (valueT) 0, &zero_address_frag);
+ &zero_address_frag, 0);
};
return GOT_symbol;
}
/* Called for any expression that can not be recognized. When the
function is called, `input_line_pointer' will point to the start of
- the expression. */
+ the expression. We use it when we have complex operations like
+ @label1 - @label2. */
void
-md_operand (expressionS *expressionP ATTRIBUTE_UNUSED)
+md_operand (expressionS *expressionP)
{
char *p = input_line_pointer;
if (*p == '@')
{
input_line_pointer++;
expressionP->X_op = O_symbol;
+ expressionP->X_md = O_absent;
expression (expressionP);
}
}
if (!assembling_insn)
return FALSE;
- if (e->X_op == O_symbol)
+ if (e->X_op == O_symbol
+ && e->X_md == O_absent)
return FALSE;
- sym = hash_find (arc_reg_hash, name);
+ sym = str_hash_find (arc_reg_hash, name);
if (sym)
{
e->X_op = O_register;
return TRUE;
}
- sym = hash_find (arc_addrtype_hash, name);
+ sym = str_hash_find (arc_addrtype_hash, name);
if (sym)
{
e->X_op = O_addrtype;
{
struct symbol *sym;
- sym = hash_find (arc_reg_hash, regname);
+ sym = str_hash_find (arc_reg_hash, regname);
if (sym)
return S_GET_VALUE (sym);
{
extRegister_t ereg;
struct arc_aux_reg *auxr;
- const char *retval;
struct arc_flag_operand *ccode;
memset (&ereg, 0, sizeof (ereg));
auxr->cpu = selected_cpu.flags;
auxr->subclass = NONE;
auxr->address = ereg.number;
- retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
- if (retval)
- as_fatal (_("internal error: can't hash aux register '%s': %s"),
- auxr->name, retval);
+ if (str_hash_insert (arc_aux_hash, auxr->name, auxr, 0) != NULL)
+ as_bad (_("duplicate aux register %s"), auxr->name);
break;
case EXT_COND_CODE:
/* Condition code. */
ext_condcode.arc_ext_condcode =
XRESIZEVEC (struct arc_flag_operand, ext_condcode.arc_ext_condcode,
ext_condcode.size + 1);
- if (ext_condcode.arc_ext_condcode == NULL)
- as_fatal (_("Virtual memory exhausted"));
ccode = ext_condcode.arc_ext_condcode + ext_condcode.size - 1;
ccode->name = ereg.name;
len += strlen (s2) + 1;
p = (char *) xmalloc (len);
- if (p == NULL)
- as_fatal (_("Virtual memory exhausted"));
if (s1)
{