mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-07-26 03:11:51 +08:00
gas: sparc: fix collision of registers and pseudo-ops.
The current sparc assembler breaks when the name of an ancillary-state register, privileged register or hyperprivileged register has a %-pseudo-operation name as a prefix. For example, %hmcdper and %hm(), or %hintp and %hi(). This patch fixes it by introducing a new table `perc_table' (for %-table) that contains an entry for every %name supported by the assembler, other than the general registers. This table is used to detect name collisions when the assembler tries to detect a %-pseudo-op. This patch also fixes a related bug, making sure that v9a_asr_table and hpriv_reg_table are sorted in reverse lexicographic order, as otherwise the search code may fail. gas/ChangeLog: 2016-06-17 Jose E. Marchesi <jose.marchesi@oracle.com> * config/tc-sparc.c (priv_reg_table): Use NULL instead of the empty string to mark the end of the array. (hpriv_reg_table): Likewise. (v9a_asr_table): Likewise. (cmp_reg_entry): Handle entries with NULL names. (F_POP_V9): Define. (F_POP_PCREL): Likewise. (F_POP_TLS_CALL): Likewise. (F_POP_POSTFIX): Likewise. (struct pop_entry): New type. (pop_table): New variable. (enum pop_entry_type): New type. (struct perc_entry): Likewise. (NUM_PERC_ENTRIES): Define. (perc_table): New variable. (cmp_perc_entry): New function. (md_begin): Sort hpriv_reg_table and v9a_asr_table, and initialize perc_table. (sparc_ip): Handle entries with NULL names in priv_reg_table, hpriv_reg_table and v9a_asr_table. Use perc_table to handle %-pseudo-ops.
This commit is contained in:
gas
@ -1,3 +1,27 @@
|
|||||||
|
2016-06-17 Jose E. Marchesi <jose.marchesi@oracle.com>
|
||||||
|
|
||||||
|
* config/tc-sparc.c (priv_reg_table): Use NULL instead of the
|
||||||
|
empty string to mark the end of the array.
|
||||||
|
(hpriv_reg_table): Likewise.
|
||||||
|
(v9a_asr_table): Likewise.
|
||||||
|
(cmp_reg_entry): Handle entries with NULL names.
|
||||||
|
(F_POP_V9): Define.
|
||||||
|
(F_POP_PCREL): Likewise.
|
||||||
|
(F_POP_TLS_CALL): Likewise.
|
||||||
|
(F_POP_POSTFIX): Likewise.
|
||||||
|
(struct pop_entry): New type.
|
||||||
|
(pop_table): New variable.
|
||||||
|
(enum pop_entry_type): New type.
|
||||||
|
(struct perc_entry): Likewise.
|
||||||
|
(NUM_PERC_ENTRIES): Define.
|
||||||
|
(perc_table): New variable.
|
||||||
|
(cmp_perc_entry): New function.
|
||||||
|
(md_begin): Sort hpriv_reg_table and v9a_asr_table, and initialize
|
||||||
|
perc_table.
|
||||||
|
(sparc_ip): Handle entries with NULL names in priv_reg_table,
|
||||||
|
hpriv_reg_table and v9a_asr_table. Use perc_table to handle
|
||||||
|
%-pseudo-ops.
|
||||||
|
|
||||||
2016-06-15 Nick Clifton <nickc@redhat.com>
|
2016-06-15 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
* config/tc-ft32.c (md_assemble): Call dwarf2_emit_insn with the
|
* config/tc-ft32.c (md_assemble): Call dwarf2_emit_insn with the
|
||||||
|
@ -807,7 +807,7 @@ struct priv_reg_entry priv_reg_table[] =
|
|||||||
{"gl", 16},
|
{"gl", 16},
|
||||||
{"pmcdper", 23},
|
{"pmcdper", 23},
|
||||||
{"ver", 31},
|
{"ver", 31},
|
||||||
{"", -1}, /* End marker. */
|
{NULL, -1}, /* End marker. */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct priv_reg_entry hpriv_reg_table[] =
|
struct priv_reg_entry hpriv_reg_table[] =
|
||||||
@ -820,11 +820,10 @@ struct priv_reg_entry hpriv_reg_table[] =
|
|||||||
{"hstick_offset", 28},
|
{"hstick_offset", 28},
|
||||||
{"hstick_enable", 29},
|
{"hstick_enable", 29},
|
||||||
{"hstick_cmpr", 31},
|
{"hstick_cmpr", 31},
|
||||||
{"", -1}, /* End marker. */
|
{NULL, -1}, /* End marker. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* v9a specific asrs. This table is ordered by initial
|
/* v9a or later specific ancillary state registers. */
|
||||||
letter, in reverse. */
|
|
||||||
|
|
||||||
struct priv_reg_entry v9a_asr_table[] =
|
struct priv_reg_entry v9a_asr_table[] =
|
||||||
{
|
{
|
||||||
@ -845,7 +844,7 @@ struct priv_reg_entry v9a_asr_table[] =
|
|||||||
{"dcr", 18},
|
{"dcr", 18},
|
||||||
{"cfr", 26},
|
{"cfr", 26},
|
||||||
{"clear_softint", 21},
|
{"clear_softint", 21},
|
||||||
{"", -1}, /* End marker. */
|
{NULL, -1}, /* End marker. */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -854,7 +853,131 @@ cmp_reg_entry (const void *parg, const void *qarg)
|
|||||||
const struct priv_reg_entry *p = (const struct priv_reg_entry *) parg;
|
const struct priv_reg_entry *p = (const struct priv_reg_entry *) parg;
|
||||||
const struct priv_reg_entry *q = (const struct priv_reg_entry *) qarg;
|
const struct priv_reg_entry *q = (const struct priv_reg_entry *) qarg;
|
||||||
|
|
||||||
return strcmp (q->name, p->name);
|
if (p->name == q->name)
|
||||||
|
return 0;
|
||||||
|
else if (p->name == NULL)
|
||||||
|
return 1;
|
||||||
|
else if (q->name == NULL)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return strcmp (q->name, p->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sparc %-pseudo-operations. */
|
||||||
|
|
||||||
|
|
||||||
|
#define F_POP_V9 0x1 /* The pseudo-op is for v9 only. */
|
||||||
|
#define F_POP_PCREL 0x2 /* The pseudo-op can be used in pc-relative
|
||||||
|
contexts. */
|
||||||
|
#define F_POP_TLS_CALL 0x4 /* The pseudo-op marks a tls call. */
|
||||||
|
#define F_POP_POSTFIX 0x8 /* The pseudo-op should appear after the
|
||||||
|
last operand of an
|
||||||
|
instruction. (Generally they can appear
|
||||||
|
anywhere an immediate operand is
|
||||||
|
expected. */
|
||||||
|
struct pop_entry
|
||||||
|
{
|
||||||
|
/* The name as it appears in assembler. */
|
||||||
|
const char *name;
|
||||||
|
/* The reloc this pseudo-op translates to. */
|
||||||
|
int reloc;
|
||||||
|
/* Flags. See F_POP_* above. */
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pop_entry pop_table[] =
|
||||||
|
{
|
||||||
|
{ "hix", BFD_RELOC_SPARC_HIX22, F_POP_V9 },
|
||||||
|
{ "lox", BFD_RELOC_SPARC_LOX10, F_POP_V9 },
|
||||||
|
{ "hi", BFD_RELOC_HI22, F_POP_PCREL },
|
||||||
|
{ "lo", BFD_RELOC_LO10, F_POP_PCREL },
|
||||||
|
{ "pc22", BFD_RELOC_SPARC_PC22, F_POP_PCREL },
|
||||||
|
{ "pc10", BFD_RELOC_SPARC_PC10, F_POP_PCREL },
|
||||||
|
{ "hh", BFD_RELOC_SPARC_HH22, F_POP_V9|F_POP_PCREL },
|
||||||
|
{ "hm", BFD_RELOC_SPARC_HM10, F_POP_V9|F_POP_PCREL },
|
||||||
|
{ "lm", BFD_RELOC_SPARC_LM22, F_POP_V9|F_POP_PCREL },
|
||||||
|
{ "h34", BFD_RELOC_SPARC_H34, F_POP_V9 },
|
||||||
|
{ "l34", BFD_RELOC_SPARC_L44, F_POP_V9 },
|
||||||
|
{ "h44", BFD_RELOC_SPARC_H44, F_POP_V9 },
|
||||||
|
{ "m44", BFD_RELOC_SPARC_M44, F_POP_V9 },
|
||||||
|
{ "l44", BFD_RELOC_SPARC_L44, F_POP_V9 },
|
||||||
|
{ "uhi", BFD_RELOC_SPARC_HH22, F_POP_V9 },
|
||||||
|
{ "ulo", BFD_RELOC_SPARC_HM10, F_POP_V9 },
|
||||||
|
{ "tgd_hi22", BFD_RELOC_SPARC_TLS_GD_HI22, 0 },
|
||||||
|
{ "tgd_lo10", BFD_RELOC_SPARC_TLS_GD_LO10, 0 },
|
||||||
|
{ "tldm_hi22", BFD_RELOC_SPARC_TLS_LDM_HI22, 0 },
|
||||||
|
{ "tldm_lo10", BFD_RELOC_SPARC_TLS_LDM_LO10, 0 },
|
||||||
|
{ "tldo_hix22", BFD_RELOC_SPARC_TLS_LDO_HIX22, 0 },
|
||||||
|
{ "tldo_lox10", BFD_RELOC_SPARC_TLS_LDO_LOX10, 0 },
|
||||||
|
{ "tie_hi22", BFD_RELOC_SPARC_TLS_IE_HI22, 0 },
|
||||||
|
{ "tie_lo10", BFD_RELOC_SPARC_TLS_IE_LO10, 0 },
|
||||||
|
{ "tle_hix22", BFD_RELOC_SPARC_TLS_LE_HIX22, 0 },
|
||||||
|
{ "tle_lox10", BFD_RELOC_SPARC_TLS_LE_LOX10, 0 },
|
||||||
|
{ "gdop_hix22", BFD_RELOC_SPARC_GOTDATA_OP_HIX22, 0 },
|
||||||
|
{ "gdop_lox10", BFD_RELOC_SPARC_GOTDATA_OP_LOX10, 0 },
|
||||||
|
{ "tgd_add", BFD_RELOC_SPARC_TLS_GD_ADD, F_POP_POSTFIX },
|
||||||
|
{ "tgd_call", BFD_RELOC_SPARC_TLS_GD_CALL, F_POP_POSTFIX|F_POP_TLS_CALL },
|
||||||
|
{ "tldm_add", BFD_RELOC_SPARC_TLS_LDM_ADD, F_POP_POSTFIX },
|
||||||
|
{ "tldm_call", BFD_RELOC_SPARC_TLS_LDM_CALL, F_POP_POSTFIX|F_POP_TLS_CALL },
|
||||||
|
{ "tldo_add", BFD_RELOC_SPARC_TLS_LDO_ADD, F_POP_POSTFIX },
|
||||||
|
{ "tie_ldx", BFD_RELOC_SPARC_TLS_IE_LDX, F_POP_POSTFIX },
|
||||||
|
{ "tie_ld", BFD_RELOC_SPARC_TLS_IE_LD, F_POP_POSTFIX },
|
||||||
|
{ "tie_add", BFD_RELOC_SPARC_TLS_IE_ADD, F_POP_POSTFIX },
|
||||||
|
{ "gdop", BFD_RELOC_SPARC_GOTDATA_OP, F_POP_POSTFIX },
|
||||||
|
{ NULL, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Table of %-names that can appear in a sparc assembly program. This
|
||||||
|
table is initialized in md_begin and contains entries for each
|
||||||
|
privileged/hyperprivileged/alternate register and %-pseudo-op. */
|
||||||
|
|
||||||
|
enum perc_entry_type
|
||||||
|
{
|
||||||
|
perc_entry_none = 0,
|
||||||
|
perc_entry_reg,
|
||||||
|
perc_entry_post_pop,
|
||||||
|
perc_entry_imm_pop
|
||||||
|
};
|
||||||
|
|
||||||
|
struct perc_entry
|
||||||
|
{
|
||||||
|
/* Entry type. */
|
||||||
|
enum perc_entry_type type;
|
||||||
|
/* Name of the %-entity. */
|
||||||
|
const char *name;
|
||||||
|
/* strlen (name). */
|
||||||
|
int len;
|
||||||
|
/* Value. Either a pop or a reg depending on type.*/
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct pop_entry *pop;
|
||||||
|
struct priv_reg_entry *reg;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUM_PERC_ENTRIES \
|
||||||
|
(((sizeof (priv_reg_table) / sizeof (priv_reg_table[0])) - 1) \
|
||||||
|
+ ((sizeof (hpriv_reg_table) / sizeof (hpriv_reg_table[0])) - 1) \
|
||||||
|
+ ((sizeof (v9a_asr_table) / sizeof (v9a_asr_table[0])) - 1) \
|
||||||
|
+ ((sizeof (pop_table) / sizeof (pop_table[0])) - 1) \
|
||||||
|
+ 1)
|
||||||
|
|
||||||
|
struct perc_entry perc_table[NUM_PERC_ENTRIES];
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmp_perc_entry (const void *parg, const void *qarg)
|
||||||
|
{
|
||||||
|
const struct perc_entry *p = (const struct perc_entry *) parg;
|
||||||
|
const struct perc_entry *q = (const struct perc_entry *) qarg;
|
||||||
|
|
||||||
|
if (p->name == q->name)
|
||||||
|
return 0;
|
||||||
|
else if (p->name == NULL)
|
||||||
|
return 1;
|
||||||
|
else if (q->name == NULL)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return strcmp (q->name, p->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called once, at assembler startup time. It should
|
/* This function is called once, at assembler startup time. It should
|
||||||
@ -932,7 +1055,11 @@ md_begin (void)
|
|||||||
|
|
||||||
qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]),
|
qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]),
|
||||||
sizeof (priv_reg_table[0]), cmp_reg_entry);
|
sizeof (priv_reg_table[0]), cmp_reg_entry);
|
||||||
|
qsort (hpriv_reg_table, sizeof (hpriv_reg_table) / sizeof (hpriv_reg_table[0]),
|
||||||
|
sizeof (hpriv_reg_table[0]), cmp_reg_entry);
|
||||||
|
qsort (v9a_asr_table, sizeof (v9a_asr_table) / sizeof (v9a_asr_table[0]),
|
||||||
|
sizeof (v9a_asr_table[0]), cmp_reg_entry);
|
||||||
|
|
||||||
/* If -bump, record the architecture level at which we start issuing
|
/* If -bump, record the architecture level at which we start issuing
|
||||||
warnings. The behaviour is different depending upon whether an
|
warnings. The behaviour is different depending upon whether an
|
||||||
architecture was explicitly specified. If it wasn't, we issue warnings
|
architecture was explicitly specified. If it wasn't, we issue warnings
|
||||||
@ -964,6 +1091,50 @@ md_begin (void)
|
|||||||
current_max_architecture))
|
current_max_architecture))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prepare the tables of %-pseudo-ops. */
|
||||||
|
{
|
||||||
|
struct priv_reg_entry *reg_tables[]
|
||||||
|
= {priv_reg_table, hpriv_reg_table, v9a_asr_table, NULL};
|
||||||
|
struct priv_reg_entry **reg_table;
|
||||||
|
int entry = 0;
|
||||||
|
|
||||||
|
/* Add registers. */
|
||||||
|
for (reg_table = reg_tables; reg_table[0]; reg_table++)
|
||||||
|
{
|
||||||
|
struct priv_reg_entry *reg;
|
||||||
|
for (reg = *reg_table; reg->name; reg++)
|
||||||
|
{
|
||||||
|
struct perc_entry *p = &perc_table[entry++];
|
||||||
|
p->type = perc_entry_reg;
|
||||||
|
p->name = reg->name;
|
||||||
|
p->len = strlen (reg->name);
|
||||||
|
p->reg = reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add %-pseudo-ops. */
|
||||||
|
{
|
||||||
|
struct pop_entry *pop;
|
||||||
|
|
||||||
|
for (pop = pop_table; pop->name; pop++)
|
||||||
|
{
|
||||||
|
struct perc_entry *p = &perc_table[entry++];
|
||||||
|
p->type = (pop->flags & F_POP_POSTFIX
|
||||||
|
? perc_entry_post_pop : perc_entry_imm_pop);
|
||||||
|
p->name = pop->name;
|
||||||
|
p->len = strlen (pop->name);
|
||||||
|
p->pop = pop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Last entry is the centinel. */
|
||||||
|
perc_table[entry].type = perc_entry_none;
|
||||||
|
|
||||||
|
qsort (perc_table, sizeof (perc_table) / sizeof (perc_table[0]),
|
||||||
|
sizeof (perc_table[0]), cmp_perc_entry);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called after all assembly has been done. */
|
/* Called after all assembly has been done. */
|
||||||
@ -1709,20 +1880,19 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
|
|||||||
/* Parse a sparc64 privileged register. */
|
/* Parse a sparc64 privileged register. */
|
||||||
if (*s == '%')
|
if (*s == '%')
|
||||||
{
|
{
|
||||||
struct priv_reg_entry *p = priv_reg_table;
|
struct priv_reg_entry *p;
|
||||||
unsigned int len = 9999999; /* Init to make gcc happy. */
|
unsigned int len = 9999999; /* Init to make gcc happy. */
|
||||||
|
|
||||||
s += 1;
|
s += 1;
|
||||||
while (p->name[0] > s[0])
|
for (p = priv_reg_table; p->name; p++)
|
||||||
p++;
|
if (p->name[0] == s[0])
|
||||||
while (p->name[0] == s[0])
|
{
|
||||||
{
|
len = strlen (p->name);
|
||||||
len = strlen (p->name);
|
if (strncmp (p->name, s, len) == 0)
|
||||||
if (strncmp (p->name, s, len) == 0)
|
break;
|
||||||
break;
|
}
|
||||||
p++;
|
|
||||||
}
|
if (!p->name)
|
||||||
if (p->name[0] != s[0])
|
|
||||||
{
|
{
|
||||||
error_message = _(": unrecognizable privileged register");
|
error_message = _(": unrecognizable privileged register");
|
||||||
goto error;
|
goto error;
|
||||||
@ -1745,20 +1915,19 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
|
|||||||
/* Parse a sparc64 hyperprivileged register. */
|
/* Parse a sparc64 hyperprivileged register. */
|
||||||
if (*s == '%')
|
if (*s == '%')
|
||||||
{
|
{
|
||||||
struct priv_reg_entry *p = hpriv_reg_table;
|
struct priv_reg_entry *p;
|
||||||
unsigned int len = 9999999; /* Init to make gcc happy. */
|
unsigned int len = 9999999; /* Init to make gcc happy. */
|
||||||
|
|
||||||
s += 1;
|
s += 1;
|
||||||
while (p->name[0] > s[0])
|
for (p = hpriv_reg_table; p->name; p++)
|
||||||
p++;
|
if (p->name[0] == s[0])
|
||||||
while (p->name[0] == s[0])
|
{
|
||||||
{
|
len = strlen (p->name);
|
||||||
len = strlen (p->name);
|
if (strncmp (p->name, s, len) == 0)
|
||||||
if (strncmp (p->name, s, len) == 0)
|
break;
|
||||||
break;
|
}
|
||||||
p++;
|
|
||||||
}
|
if (!p->name)
|
||||||
if (p->name[0] != s[0])
|
|
||||||
{
|
{
|
||||||
error_message = _(": unrecognizable hyperprivileged register");
|
error_message = _(": unrecognizable hyperprivileged register");
|
||||||
goto error;
|
goto error;
|
||||||
@ -1781,20 +1950,19 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
|
|||||||
/* Parse a v9a/v9b ancillary state register. */
|
/* Parse a v9a/v9b ancillary state register. */
|
||||||
if (*s == '%')
|
if (*s == '%')
|
||||||
{
|
{
|
||||||
struct priv_reg_entry *p = v9a_asr_table;
|
struct priv_reg_entry *p;
|
||||||
unsigned int len = 9999999; /* Init to make gcc happy. */
|
unsigned int len = 9999999; /* Init to make gcc happy. */
|
||||||
|
|
||||||
s += 1;
|
s += 1;
|
||||||
while (p->name[0] > s[0])
|
for (p = v9a_asr_table; p->name; p++)
|
||||||
p++;
|
if (p->name[0] == s[0])
|
||||||
while (p->name[0] == s[0])
|
{
|
||||||
{
|
len = strlen (p->name);
|
||||||
len = strlen (p->name);
|
if (strncmp (p->name, s, len) == 0)
|
||||||
if (strncmp (p->name, s, len) == 0)
|
break;
|
||||||
break;
|
}
|
||||||
p++;
|
|
||||||
}
|
if (!p->name)
|
||||||
if (p->name[0] != s[0])
|
|
||||||
{
|
{
|
||||||
error_message = _(": unrecognizable v9a or v9b ancillary state register");
|
error_message = _(": unrecognizable v9a or v9b ancillary state register");
|
||||||
goto error;
|
goto error;
|
||||||
@ -2062,67 +2230,45 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
|
|||||||
case '\0': /* End of args. */
|
case '\0': /* End of args. */
|
||||||
if (s[0] == ',' && s[1] == '%')
|
if (s[0] == ',' && s[1] == '%')
|
||||||
{
|
{
|
||||||
static const struct ops
|
|
||||||
{
|
|
||||||
/* The name as it appears in assembler. */
|
|
||||||
const char *name;
|
|
||||||
/* strlen (name), precomputed for speed */
|
|
||||||
int len;
|
|
||||||
/* The reloc this pseudo-op translates to. */
|
|
||||||
int reloc;
|
|
||||||
/* 1 if tls call. */
|
|
||||||
int tls_call;
|
|
||||||
}
|
|
||||||
ops[] =
|
|
||||||
{
|
|
||||||
{ "tgd_add", 7, BFD_RELOC_SPARC_TLS_GD_ADD, 0 },
|
|
||||||
{ "tgd_call", 8, BFD_RELOC_SPARC_TLS_GD_CALL, 1 },
|
|
||||||
{ "tldm_add", 8, BFD_RELOC_SPARC_TLS_LDM_ADD, 0 },
|
|
||||||
{ "tldm_call", 9, BFD_RELOC_SPARC_TLS_LDM_CALL, 1 },
|
|
||||||
{ "tldo_add", 8, BFD_RELOC_SPARC_TLS_LDO_ADD, 0 },
|
|
||||||
{ "tie_ldx", 7, BFD_RELOC_SPARC_TLS_IE_LDX, 0 },
|
|
||||||
{ "tie_ld", 6, BFD_RELOC_SPARC_TLS_IE_LD, 0 },
|
|
||||||
{ "tie_add", 7, BFD_RELOC_SPARC_TLS_IE_ADD, 0 },
|
|
||||||
{ "gdop", 4, BFD_RELOC_SPARC_GOTDATA_OP, 0 },
|
|
||||||
{ NULL, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
const struct ops *o;
|
|
||||||
char *s1;
|
char *s1;
|
||||||
int npar = 0;
|
int npar = 0;
|
||||||
|
const struct perc_entry *p;
|
||||||
|
|
||||||
for (o = ops; o->name; o++)
|
for (p = perc_table; p->type != perc_entry_none; p++)
|
||||||
if (strncmp (s + 2, o->name, o->len) == 0)
|
if ((p->type == perc_entry_post_pop || p->type == perc_entry_reg)
|
||||||
break;
|
&& strncmp (s + 2, p->name, p->len) == 0)
|
||||||
if (o->name == NULL)
|
break;
|
||||||
break;
|
if (p->type == perc_entry_none || p->type == perc_entry_reg)
|
||||||
|
break;
|
||||||
|
|
||||||
if (s[o->len + 2] != '(')
|
if (s[p->len + 2] != '(')
|
||||||
{
|
{
|
||||||
as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
|
as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name);
|
||||||
return special_case;
|
return special_case;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! o->tls_call && the_insn.reloc != BFD_RELOC_NONE)
|
if (! (p->pop->flags & F_POP_TLS_CALL)
|
||||||
|
&& the_insn.reloc != BFD_RELOC_NONE)
|
||||||
{
|
{
|
||||||
as_bad (_("Illegal operands: %%%s cannot be used together with other relocs in the insn ()"),
|
as_bad (_("Illegal operands: %%%s cannot be used together with other relocs in the insn ()"),
|
||||||
o->name);
|
p->name);
|
||||||
return special_case;
|
return special_case;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o->tls_call
|
if ((p->pop->flags & F_POP_TLS_CALL)
|
||||||
&& (the_insn.reloc != BFD_RELOC_32_PCREL_S2
|
&& (the_insn.reloc != BFD_RELOC_32_PCREL_S2
|
||||||
|| the_insn.exp.X_add_number != 0
|
|| the_insn.exp.X_add_number != 0
|
||||||
|| the_insn.exp.X_add_symbol
|
|| the_insn.exp.X_add_symbol
|
||||||
!= symbol_find_or_make ("__tls_get_addr")))
|
!= symbol_find_or_make ("__tls_get_addr")))
|
||||||
{
|
{
|
||||||
as_bad (_("Illegal operands: %%%s can be only used with call __tls_get_addr"),
|
as_bad (_("Illegal operands: %%%s can be only used with call __tls_get_addr"),
|
||||||
o->name);
|
p->name);
|
||||||
return special_case;
|
return special_case;
|
||||||
}
|
}
|
||||||
|
|
||||||
the_insn.reloc = o->reloc;
|
the_insn.reloc = p->pop->reloc;
|
||||||
memset (&the_insn.exp, 0, sizeof (the_insn.exp));
|
memset (&the_insn.exp, 0, sizeof (the_insn.exp));
|
||||||
s += o->len + 3;
|
s += p->len + 3;
|
||||||
|
|
||||||
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
|
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
|
||||||
if (*s1 == '(')
|
if (*s1 == '(')
|
||||||
@ -2136,7 +2282,7 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
|
|||||||
|
|
||||||
if (*s1 != ')')
|
if (*s1 != ')')
|
||||||
{
|
{
|
||||||
as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
|
as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name);
|
||||||
return special_case;
|
return special_case;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2525,72 +2671,25 @@ sparc_ip (char *str, const struct sparc_opcode **pinsn)
|
|||||||
/* Check for %hi, etc. */
|
/* Check for %hi, etc. */
|
||||||
if (*s == '%')
|
if (*s == '%')
|
||||||
{
|
{
|
||||||
static const struct ops {
|
const struct perc_entry *p;
|
||||||
/* The name as it appears in assembler. */
|
|
||||||
const char *name;
|
for (p = perc_table; p->type != perc_entry_none; p++)
|
||||||
/* strlen (name), precomputed for speed */
|
if ((p->type == perc_entry_imm_pop || p->type == perc_entry_reg)
|
||||||
int len;
|
&& strncmp (s + 1, p->name, p->len) == 0)
|
||||||
/* The reloc this pseudo-op translates to. */
|
break;
|
||||||
int reloc;
|
if (p->type == perc_entry_none || p->type == perc_entry_reg)
|
||||||
/* Non-zero if for v9 only. */
|
break;
|
||||||
int v9_p;
|
|
||||||
/* Non-zero if can be used in pc-relative contexts. */
|
|
||||||
int pcrel_p;/*FIXME:wip*/
|
|
||||||
} ops[] = {
|
|
||||||
/* hix/lox must appear before hi/lo so %hix won't be
|
|
||||||
mistaken for %hi. */
|
|
||||||
{ "hix", 3, BFD_RELOC_SPARC_HIX22, 1, 0 },
|
|
||||||
{ "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 },
|
|
||||||
{ "hi", 2, BFD_RELOC_HI22, 0, 1 },
|
|
||||||
{ "lo", 2, BFD_RELOC_LO10, 0, 1 },
|
|
||||||
{ "pc22", 4, BFD_RELOC_SPARC_PC22, 0, 1 },
|
|
||||||
{ "pc10", 4, BFD_RELOC_SPARC_PC10, 0, 1 },
|
|
||||||
{ "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 },
|
|
||||||
{ "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 },
|
|
||||||
{ "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 },
|
|
||||||
{ "h34", 3, BFD_RELOC_SPARC_H34, 1, 0 },
|
|
||||||
{ "l34", 3, BFD_RELOC_SPARC_L44, 1, 0 },
|
|
||||||
{ "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 },
|
|
||||||
{ "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 },
|
|
||||||
{ "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 },
|
|
||||||
{ "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 },
|
|
||||||
{ "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 },
|
|
||||||
{ "tgd_hi22", 8, BFD_RELOC_SPARC_TLS_GD_HI22, 0, 0 },
|
|
||||||
{ "tgd_lo10", 8, BFD_RELOC_SPARC_TLS_GD_LO10, 0, 0 },
|
|
||||||
{ "tldm_hi22", 9, BFD_RELOC_SPARC_TLS_LDM_HI22, 0, 0 },
|
|
||||||
{ "tldm_lo10", 9, BFD_RELOC_SPARC_TLS_LDM_LO10, 0, 0 },
|
|
||||||
{ "tldo_hix22", 10, BFD_RELOC_SPARC_TLS_LDO_HIX22, 0,
|
|
||||||
0 },
|
|
||||||
{ "tldo_lox10", 10, BFD_RELOC_SPARC_TLS_LDO_LOX10, 0,
|
|
||||||
0 },
|
|
||||||
{ "tie_hi22", 8, BFD_RELOC_SPARC_TLS_IE_HI22, 0, 0 },
|
|
||||||
{ "tie_lo10", 8, BFD_RELOC_SPARC_TLS_IE_LO10, 0, 0 },
|
|
||||||
{ "tle_hix22", 9, BFD_RELOC_SPARC_TLS_LE_HIX22, 0, 0 },
|
|
||||||
{ "tle_lox10", 9, BFD_RELOC_SPARC_TLS_LE_LOX10, 0, 0 },
|
|
||||||
{ "gdop_hix22", 10, BFD_RELOC_SPARC_GOTDATA_OP_HIX22,
|
|
||||||
0, 0 },
|
|
||||||
{ "gdop_lox10", 10, BFD_RELOC_SPARC_GOTDATA_OP_LOX10,
|
|
||||||
0, 0 },
|
|
||||||
{ NULL, 0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
const struct ops *o;
|
|
||||||
|
|
||||||
for (o = ops; o->name; o++)
|
if (s[p->len + 1] != '(')
|
||||||
if (strncmp (s + 1, o->name, o->len) == 0)
|
|
||||||
break;
|
|
||||||
if (o->name == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (s[o->len + 1] != '(')
|
|
||||||
{
|
{
|
||||||
as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
|
as_bad (_("Illegal operands: %%%s requires arguments in ()"), p->name);
|
||||||
return special_case;
|
return special_case;
|
||||||
}
|
}
|
||||||
|
|
||||||
op_arg = o->name;
|
op_arg = p->name;
|
||||||
the_insn.reloc = o->reloc;
|
the_insn.reloc = p->pop->reloc;
|
||||||
s += o->len + 2;
|
s += p->len + 2;
|
||||||
v9_arg_p = o->v9_p;
|
v9_arg_p = p->pop->flags & F_POP_V9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note that if the get_expression() fails, we will still
|
/* Note that if the get_expression() fails, we will still
|
||||||
|
Reference in New Issue
Block a user