Jakub Jelinek <jj@ultra.linux.cz>

* config/tc-sparc.c (md_begin): Handle native wordsize aliases.
        (s_ncons): New function.
        (native_op_table): New table.
        (sparc_ip): Be more strict on %hi() etc.; prepare assembler for
        R_SPARC_OLO10 handling.
This commit is contained in:
Richard Henderson
1999-06-07 12:40:36 +00:00
parent bed2c8562a
commit cf9a13018b
2 changed files with 266 additions and 78 deletions

View File

@ -1,3 +1,11 @@
1999-06-07 Jakub Jelinek <jj@ultra.linux.cz>
* config/tc-sparc.c (md_begin): Handle native wordsize aliases.
(s_ncons): New function.
(native_op_table): New table.
(sparc_ip): Be more strict on %hi() etc.; prepare assembler for
R_SPARC_OLO10 handling.
Mon Jun 7 10:22:16 1999 Richard Henderson <rth@cygnus.com> Mon Jun 7 10:22:16 1999 Richard Henderson <rth@cygnus.com>
* expr.h (struct expressionS): Revert last change; widen X_op. * expr.h (struct expressionS): Revert last change; widen X_op.

View File

@ -115,6 +115,7 @@ static void s_reserve PARAMS ((int));
static void s_common PARAMS ((int)); static void s_common PARAMS ((int));
static void s_empty PARAMS ((int)); static void s_empty PARAMS ((int));
static void s_uacons PARAMS ((int)); static void s_uacons PARAMS ((int));
static void s_ncons PARAMS ((int));
const pseudo_typeS md_pseudo_table[] = const pseudo_typeS md_pseudo_table[] =
{ {
@ -123,6 +124,7 @@ const pseudo_typeS md_pseudo_table[] =
{"empty", s_empty, 0}, {"empty", s_empty, 0},
{"global", s_globl, 0}, {"global", s_globl, 0},
{"half", cons, 2}, {"half", cons, 2},
{"nword", s_ncons, 0},
{"optim", s_ignore, 0}, {"optim", s_ignore, 0},
{"proc", s_proc, 0}, {"proc", s_proc, 0},
{"reserve", s_reserve, 0}, {"reserve", s_reserve, 0},
@ -174,9 +176,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
changed in read.c. Ideally it shouldn't have to know about it at all, changed in read.c. Ideally it shouldn't have to know about it at all,
but nothing is ideal around here. */ but nothing is ideal around here. */
static unsigned char octal[256]; #define isoctal(c) ((c) >= '0' && (c) < '8')
#define isoctal(c) octal[(unsigned char) (c)]
static unsigned char toHex[256];
struct sparc_it struct sparc_it
{ {
@ -184,6 +184,7 @@ struct sparc_it
unsigned long opcode; unsigned long opcode;
struct nlist *nlistp; struct nlist *nlistp;
expressionS exp; expressionS exp;
expressionS exp2;
int pcrel; int pcrel;
bfd_reloc_code_real_type reloc; bfd_reloc_code_real_type reloc;
}; };
@ -613,6 +614,27 @@ md_show_usage (stream)
#endif #endif
} }
/* native operand size opcode translation */
struct
{
char *name;
char *name32;
char *name64;
} native_op_table[] =
{
{"ldn", "ld", "ldx"},
{"ldna", "lda", "ldxa"},
{"stn", "st", "stx"},
{"stna", "sta", "stxa"},
{"slln", "sll", "sllx"},
{"srln", "srl", "srlx"},
{"sran", "sra", "srax"},
{"casn", "cas", "casx"},
{"casna", "casa", "casxa"},
{"clrn", "clr", "clrx"},
{NULL, NULL, NULL},
};
/* sparc64 priviledged registers */ /* sparc64 priviledged registers */
struct priv_reg_entry struct priv_reg_entry
@ -693,16 +715,16 @@ md_begin ()
retval = hash_insert (op_hash, name, (PTR) &sparc_opcodes[i]); retval = hash_insert (op_hash, name, (PTR) &sparc_opcodes[i]);
if (retval != NULL) if (retval != NULL)
{ {
fprintf (stderr, _("internal error: can't hash `%s': %s\n"), as_bad (_("Internal error: can't hash `%s': %s\n"),
sparc_opcodes[i].name, retval); sparc_opcodes[i].name, retval);
lose = 1; lose = 1;
} }
do do
{ {
if (sparc_opcodes[i].match & sparc_opcodes[i].lose) if (sparc_opcodes[i].match & sparc_opcodes[i].lose)
{ {
fprintf (stderr, _("internal error: losing opcode: `%s' \"%s\"\n"), as_bad (_("Internal error: losing opcode: `%s' \"%s\"\n"),
sparc_opcodes[i].name, sparc_opcodes[i].args); sparc_opcodes[i].name, sparc_opcodes[i].args);
lose = 1; lose = 1;
} }
++i; ++i;
@ -711,18 +733,33 @@ md_begin ()
&& !strcmp (sparc_opcodes[i].name, name)); && !strcmp (sparc_opcodes[i].name, name));
} }
for (i = 0; native_op_table[i].name; i++)
{
const struct sparc_opcode *insn;
char *name = sparc_arch_size == 32 ? native_op_table[i].name32 :
native_op_table[i].name64;
insn = (struct sparc_opcode *)hash_find (op_hash, name);
if (insn == NULL)
{
as_bad (_("Internal error: can't find opcode `%s' for `%s'\n"),
name, native_op_table[i].name);
lose = 1;
}
else
{
retval = hash_insert (op_hash, native_op_table[i].name, (PTR) insn);
if (retval != NULL)
{
as_bad (_("Internal error: can't hash `%s': %s\n"),
sparc_opcodes[i].name, retval);
lose = 1;
}
}
}
if (lose) if (lose)
as_fatal (_("Broken assembler. No assembly attempted.")); as_fatal (_("Broken assembler. No assembly attempted."));
for (i = '0'; i < '8'; ++i)
octal[i] = 1;
for (i = '0'; i <= '9'; ++i)
toHex[i] = i - '0';
for (i = 'a'; i <= 'f'; ++i)
toHex[i] = i + 10 - 'a';
for (i = 'A'; i <= 'F'; ++i)
toHex[i] = i + 10 - 'A';
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);
@ -1885,89 +1922,221 @@ sparc_ip (str, pinsn)
if (*s == ' ') if (*s == ' ')
s++; s++;
/* Check for %hi, etc. */
if (*s == '%')
{
static struct ops {
/* The name as it appears in assembler. */
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 },
{ "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 },
{ "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 },
{ "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 },
{ "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 },
{ NULL }
};
struct ops *o;
for (o = ops; o->name; o++)
if (strncmp (s + 1, o->name, o->len) == 0)
break;
if (o->name == NULL)
break;
the_insn.reloc = o->reloc;
s += o->len + 1;
v9_arg_p = o->v9_p;
}
/* Note that if the get_expression() fails, we will still
have created U entries in the symbol table for the
'symbols' in the input string. Try not to create U
symbols for registers, etc. */
{ {
char *s1;
char *op_arg = NULL;
expressionS op_exp;
bfd_reloc_code_real_type old_reloc = the_insn.reloc;
/* Check for %hi, etc. */
if (*s == '%')
{
static const struct ops {
/* The name as it appears in assembler. */
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 },
{ "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 },
{ "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 },
{ "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 },
{ "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 },
{ NULL }
};
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] != '(')
{
as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name);
return;
}
op_arg = o->name;
the_insn.reloc = o->reloc;
s += o->len + 2;
v9_arg_p = o->v9_p;
}
/* Note that if the get_expression() fails, we will still
have created U entries in the symbol table for the
'symbols' in the input string. Try not to create U
symbols for registers, etc. */
/* This stuff checks to see if the expression ends in /* This stuff checks to see if the expression ends in
+%reg. If it does, it removes the register from +%reg. If it does, it removes the register from
the expression, and re-sets 's' to point to the the expression, and re-sets 's' to point to the
right place. */ right place. */
char *s1; if (op_arg)
{
int npar = 0;
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++)
if (*s1 == '(')
npar++;
else if (*s1 == ')')
{
if (!npar)
break;
npar--;
}
if (*s1 != ')')
{
as_bad (_("Illegal operands: %%%s requires arguments in ()"), op_arg);
return;
}
*s1 = '\0';
(void) get_expression (s);
*s1 = ')';
s = s1 + 1;
if (*s == ',' || *s == ']' || !*s)
continue;
if (*s != '+' && *s != '-')
{
as_bad (_("Illegal operands: Can't do arithmetics other than + and - involving %%%s()"), op_arg);
return;
}
*s1 = '0';
s = s1;
op_exp = the_insn.exp;
memset (&the_insn.exp, 0, sizeof(the_insn.exp));
}
for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ; for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ;
if (s1 != s && isdigit ((unsigned char) s1[-1])) if (s1 != s && isdigit ((unsigned char) s1[-1]))
{ {
if (s1[-2] == '%' && s1[-3] == '+') if (s1[-2] == '%' && s1[-3] == '+')
{ s1 -= 3;
s1 -= 3;
*s1 = '\0';
(void) get_expression (s);
*s1 = '+';
s = s1;
continue;
}
else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+') else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+')
s1 -= 4;
else
s1 = NULL;
if (s1)
{ {
s1 -= 4;
*s1 = '\0'; *s1 = '\0';
(void) get_expression (s); (void) get_expression (s);
*s1 = '+'; *s1 = '+';
if (op_arg)
*s = ')';
s = s1; s = s1;
continue; }
}
else
s1 = NULL;
if (!s1)
{
(void) get_expression (s);
if (op_arg)
*s = ')';
s = expr_end;
}
if (op_arg)
{
the_insn.exp2 = the_insn.exp;
the_insn.exp = op_exp;
if (the_insn.exp2.X_op == O_absent)
the_insn.exp2.X_op = O_illegal;
else if (the_insn.exp.X_op == O_absent)
{
the_insn.exp = the_insn.exp2;
the_insn.exp2.X_op = O_illegal;
}
else if (the_insn.exp.X_op == O_constant)
{
valueT val = the_insn.exp.X_add_number;
switch (the_insn.reloc)
{
case BFD_RELOC_SPARC_HH22:
val = BSR (val, 32);
/* intentional fallthrough */
case BFD_RELOC_SPARC_LM22:
case BFD_RELOC_HI22:
val = (val >> 10) & 0x3fffff;
break;
case BFD_RELOC_SPARC_HM10:
val = BSR (val, 32);
/* intentional fallthrough */
case BFD_RELOC_LO10:
val &= 0x3ff;
break;
case BFD_RELOC_SPARC_H44:
val >>= 22;
val &= 0x3fffff;
break;
case BFD_RELOC_SPARC_M44:
val >>= 12;
val &= 0x3ff;
break;
case BFD_RELOC_SPARC_L44:
val &= 0xfff;
break;
case BFD_RELOC_SPARC_HIX22:
val = ~ val;
val = (val >> 10) & 0x3fffff;
break;
case BFD_RELOC_SPARC_LOX10:
val = (val & 0x3ff) | 0x1c00;
break;
}
the_insn.exp = the_insn.exp2;
the_insn.exp.X_add_number += val;
the_insn.exp2.X_op = O_illegal;
the_insn.reloc = old_reloc;
}
else if (the_insn.exp2.X_op != O_constant)
{
as_bad (_("Illegal operands: Can't add non-constant expression to %%%s()"), op_arg);
return;
}
else
{
if (1 || old_reloc != BFD_RELOC_SPARC13
|| the_insn.reloc != BFD_RELOC_LO10
|| sparc_arch_size != 64
|| sparc_pic_code)
{
as_bad (_("Illegal operands: Can't do arithmetics involving %%%s() of a relocatable symbol"), op_arg);
return;
}
the_insn.reloc = BFD_RELOC_SPARC_OLO10;
} }
} }
} }
(void) get_expression (s);
s = expr_end;
/* Check for constants that don't require emitting a reloc. */ /* Check for constants that don't require emitting a reloc. */
if (the_insn.exp.X_op == O_constant if (the_insn.exp.X_op == O_constant
&& the_insn.exp.X_add_symbol == 0 && the_insn.exp.X_add_symbol == 0
@ -3395,6 +3564,17 @@ s_uacons (bytes)
cons (bytes); cons (bytes);
} }
/* This handles the native word allocation pseudo-op .nword.
For sparc_arch_size 32 it is equivalent to .word, for
sparc_arch_size 64 it is equivalent to .xword. */
static void
s_ncons (bytes)
int bytes;
{
cons (sparc_arch_size == 32 ? 4 : 8);
}
/* If the --enforce-aligned-data option is used, we require .word, /* If the --enforce-aligned-data option is used, we require .word,
et. al., to be aligned correctly. We do it by setting up an et. al., to be aligned correctly. We do it by setting up an
rs_align_code frag, and checking in HANDLE_ALIGN to make sure that rs_align_code frag, and checking in HANDLE_ALIGN to make sure that