Skip to content

Commit

Permalink
[ARC][committed] Improve parsing instruction operands.
Browse files Browse the repository at this point in the history
We use gas' expression function to parse the operands of an
instruction in a generic way. There are situations when we have labels
and registers having the same name as well as the substraction sign
doesn't always stands for the arithmetical operation but for the
register range (e.g. enter instruction). This patch improves parsing
symbols found in a instruction operand.

gas/
xxxx-xx-xx  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/tc-arc.c (parse_reloc_symbol): New function.
	(tokenize_arguments): Clean up, use parse_reloc_symbol function.
	(md_operand): Set X_md to absent.
	(arc_parse_name): Check for X_md.
  • Loading branch information
claziss committed Dec 20, 2019
1 parent 2eb78e0 commit 91be564
Showing 1 changed file with 110 additions and 91 deletions.
201 changes: 110 additions & 91 deletions gas/config/tc-arc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,102 @@ debug_exp (expressionS *t)
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
Expand All @@ -1111,11 +1207,6 @@ tokenize_arguments (char *str,
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);

Expand Down Expand Up @@ -1177,95 +1268,21 @@ tokenize_arguments (char *str,
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++;
Expand All @@ -1289,9 +1306,8 @@ tokenize_arguments (char *str,
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
Expand Down Expand Up @@ -3329,16 +3345,18 @@ md_atof (int type, char *litP, int *sizeP)

/* 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);
}
}
Expand All @@ -3357,7 +3375,8 @@ arc_parse_name (const char *name,
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);
Expand Down

0 comments on commit 91be564

Please sign in to comment.