{"gl", 16},
{"pmcdper", 23},
{"ver", 31},
- {"", -1}, /* End marker. */
+ {NULL, -1}, /* End marker. */
};
struct priv_reg_entry hpriv_reg_table[] =
{"hstick_offset", 28},
{"hstick_enable", 29},
{"hstick_cmpr", 31},
- {"", -1}, /* End marker. */
+ {NULL, -1}, /* End marker. */
};
-/* v9a specific asrs. This table is ordered by initial
- letter, in reverse. */
+/* v9a or later specific ancillary state registers. */
struct priv_reg_entry v9a_asr_table[] =
{
{"dcr", 18},
{"cfr", 26},
{"clear_softint", 21},
- {"", -1}, /* End marker. */
+ {NULL, -1}, /* End marker. */
};
static int
const struct priv_reg_entry *p = (const struct priv_reg_entry *) parg;
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);
+}
+\f
+/* 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 },
+};
+\f
+/* 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);
}
\f
/* This function is called once, at assembler startup time. It should
qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]),
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
warnings. The behaviour is different depending upon whether an
architecture was explicitly specified. If it wasn't, we issue warnings
current_max_architecture))
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. */
/* Parse a sparc64 privileged register. */
if (*s == '%')
{
- struct priv_reg_entry *p = priv_reg_table;
+ struct priv_reg_entry *p;
unsigned int len = 9999999; /* Init to make gcc happy. */
s += 1;
- while (p->name[0] > s[0])
- p++;
- while (p->name[0] == s[0])
- {
- len = strlen (p->name);
- if (strncmp (p->name, s, len) == 0)
- break;
- p++;
- }
- if (p->name[0] != s[0])
+ for (p = priv_reg_table; p->name; p++)
+ if (p->name[0] == s[0])
+ {
+ len = strlen (p->name);
+ if (strncmp (p->name, s, len) == 0)
+ break;
+ }
+
+ if (!p->name)
{
error_message = _(": unrecognizable privileged register");
goto error;
/* Parse a sparc64 hyperprivileged register. */
if (*s == '%')
{
- struct priv_reg_entry *p = hpriv_reg_table;
+ struct priv_reg_entry *p;
unsigned int len = 9999999; /* Init to make gcc happy. */
s += 1;
- while (p->name[0] > s[0])
- p++;
- while (p->name[0] == s[0])
- {
- len = strlen (p->name);
- if (strncmp (p->name, s, len) == 0)
- break;
- p++;
- }
- if (p->name[0] != s[0])
+ for (p = hpriv_reg_table; p->name; p++)
+ if (p->name[0] == s[0])
+ {
+ len = strlen (p->name);
+ if (strncmp (p->name, s, len) == 0)
+ break;
+ }
+
+ if (!p->name)
{
error_message = _(": unrecognizable hyperprivileged register");
goto error;
/* Parse a v9a/v9b ancillary state register. */
if (*s == '%')
{
- struct priv_reg_entry *p = v9a_asr_table;
+ struct priv_reg_entry *p;
unsigned int len = 9999999; /* Init to make gcc happy. */
s += 1;
- while (p->name[0] > s[0])
- p++;
- while (p->name[0] == s[0])
- {
- len = strlen (p->name);
- if (strncmp (p->name, s, len) == 0)
- break;
- p++;
- }
- if (p->name[0] != s[0])
+ for (p = v9a_asr_table; p->name; p++)
+ if (p->name[0] == s[0])
+ {
+ len = strlen (p->name);
+ if (strncmp (p->name, s, len) == 0)
+ break;
+ }
+
+ if (!p->name)
{
error_message = _(": unrecognizable v9a or v9b ancillary state register");
goto error;
case '\0': /* End of args. */
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;
int npar = 0;
+ const struct perc_entry *p;
- for (o = ops; o->name; o++)
- if (strncmp (s + 2, o->name, o->len) == 0)
- break;
- if (o->name == NULL)
- break;
+ for (p = perc_table; p->type != perc_entry_none; p++)
+ if ((p->type == perc_entry_post_pop || p->type == perc_entry_reg)
+ && strncmp (s + 2, p->name, p->len) == 0)
+ 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;
}
- 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 ()"),
- o->name);
+ p->name);
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.exp.X_add_number != 0
|| the_insn.exp.X_add_symbol
!= symbol_find_or_make ("__tls_get_addr")))
{
as_bad (_("Illegal operands: %%%s can be only used with call __tls_get_addr"),
- o->name);
+ p->name);
return special_case;
}
- the_insn.reloc = o->reloc;
+ the_insn.reloc = p->pop->reloc;
memset (&the_insn.exp, 0, sizeof (the_insn.exp));
- s += o->len + 3;
+ s += p->len + 3;
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
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;
}
/* Check for %hi, etc. */
if (*s == '%')
{
- 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;
- /* Non-zero if for v9 only. */
- 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 (strncmp (s + 1, o->name, o->len) == 0)
- break;
- if (o->name == NULL)
- break;
-
- if (s[o->len + 1] != '(')
+ const struct perc_entry *p;
+
+ for (p = perc_table; p->type != perc_entry_none; p++)
+ if ((p->type == perc_entry_imm_pop || p->type == perc_entry_reg)
+ && strncmp (s + 1, p->name, p->len) == 0)
+ break;
+ if (p->type == perc_entry_none || p->type == perc_entry_reg)
+ break;
+
+ if (s[p->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;
}
- op_arg = o->name;
- the_insn.reloc = o->reloc;
- s += o->len + 2;
- v9_arg_p = o->v9_p;
+ op_arg = p->name;
+ the_insn.reloc = p->pop->reloc;
+ s += p->len + 2;
+ v9_arg_p = p->pop->flags & F_POP_V9;
}
/* Note that if the get_expression() fails, we will still