/* tc-sparc.c -- Assemble for the SPARC
Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
to the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
-#include <stdio.h>
-
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
{NULL, 0, 0},
};
-/* Size of relocation record. */
-const int md_reloc_size = 12;
-
/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful. */
const char comment_chars[] = "!"; /* JF removed '|' from
changed in read.c. Ideally it shouldn't have to know about it at all,
but nothing is ideal around here. */
-#define isoctal(c) ((unsigned) ((c) - '0') < '8')
+#define isoctal(c) ((unsigned) ((c) - '0') < 8)
struct sparc_it
{
#endif
#endif
+#ifdef TE_VXWORKS
+ return "elf32-sparc-vxworks";
+#endif
+
#ifdef OBJ_ELF
- return sparc_arch_size == 64 ? "elf64-sparc" : "elf32-sparc";
+ return sparc_arch_size == 64 ? ELF64_TARGET_FORMAT : ELF_TARGET_FORMAT;
#endif
abort ();
{
if (sparc_arch_size == 32)
{
- if (strcmp (*l, "elf32-sparc") == 0)
+ if (CONST_STRNEQ (*l, "elf32-sparc"))
break;
}
else
{
- if (strcmp (*l, "elf64-sparc") == 0)
+ if (CONST_STRNEQ (*l, "elf64-sparc"))
break;
}
}
{NULL, NULL, NULL},
};
\f
-/* sparc64 privileged registers. */
+/* sparc64 privileged and hyperprivileged registers. */
struct priv_reg_entry
{
{"otherwin", 13},
{"wstate", 14},
{"fq", 15},
+ {"gl", 16},
{"ver", 31},
{"", -1}, /* End marker. */
};
+struct priv_reg_entry hpriv_reg_table[] =
+{
+ {"hpstate", 0},
+ {"htstate", 1},
+ {"hintp", 3},
+ {"htba", 5},
+ {"hver", 6},
+ {"hstick_cmpr", 31},
+ {"", -1}, /* End marker. */
+};
+
/* v9a specific asrs. */
struct priv_reg_entry v9a_asr_table[] =
goto error;
}
+ case '$':
+ case '%':
+ /* Parse a sparc64 hyperprivileged register. */
+ if (*s == '%')
+ {
+ struct priv_reg_entry *p = hpriv_reg_table;
+ 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])
+ {
+ error_message = _(": unrecognizable hyperprivileged register");
+ goto error;
+ }
+ if (*args == '$')
+ opcode |= (p->regnum << 14);
+ else
+ opcode |= (p->regnum << 25);
+ s += len;
+ continue;
+ }
+ else
+ {
+ error_message = _(": unrecognizable hyperprivileged register");
+ goto error;
+ }
+
case '_':
case '/':
/* Parse a v9a/v9b ancillary state register. */
case '\0': /* End of args. */
if (s[0] == ',' && s[1] == '%')
{
- static const struct tls_ops {
+ static const struct tls_ops
+ {
/* The name as it appears in assembler. */
char *name;
/* strlen (name), precomputed for speed */
int reloc;
/* 1 if call. */
int call;
- } tls_ops[] = {
+ }
+ tls_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 },
{ "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 }
+ { "tie_add", 7, BFD_RELOC_SPARC_TLS_IE_ADD, 0 },
+ { NULL, 0, 0, 0 }
};
const struct tls_ops *o;
char *s1;
#endif
}
\f
-/* This is identical to the md_atof in m68k.c. I think this is right,
- but I'm not sure.
-
- Turn a string in input_line_pointer into a floating point constant
- of type TYPE, and store the appropriate bytes in *LITP. The number
- of LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
-
-/* Equal to MAX_PRECISION in atof-ieee.c. */
-#define MAX_LITTLENUMS 6
-
char *
-md_atof (type, litP, sizeP)
- char type;
- char *litP;
- int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
{
- int i, prec;
- LITTLENUM_TYPE words[MAX_LITTLENUMS];
- char *t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- case 's':
- case 'S':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- prec = 4;
- break;
-
- case 'x':
- case 'X':
- prec = 6;
- break;
-
- case 'p':
- case 'P':
- prec = 6;
- break;
-
- default:
- *sizeP = 0;
- return _("Bad call to MD_ATOF()");
- }
-
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
- *sizeP = prec * sizeof (LITTLENUM_TYPE);
-
- if (target_big_endian)
- {
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i],
- sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- }
- else
- {
- for (i = prec - 1; i >= 0; i--)
- {
- md_number_to_chars (litP, (valueT) words[i],
- sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- }
-
- return 0;
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
/* Write a value out to the object file, using the appropriate
break;
case BFD_RELOC_SPARC_WDISP16:
- /* FIXME: simplify. */
- if (((val > 0) && (val & ~0x3fffc))
- || ((val < 0) && (~(val - 1) & ~0x3fffc)))
+ if ((val & 3)
+ || val >= 0x1fffc
+ || val <= -(offsetT) 0x20008)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("relocation overflow"));
/* FIXME: The +1 deserves a comment. */
break;
case BFD_RELOC_SPARC_WDISP19:
- /* FIXME: simplify. */
- if (((val > 0) && (val & ~0x1ffffc))
- || ((val < 0) && (~(val - 1) & ~0x1ffffc)))
+ if ((val & 3)
+ || val >= 0xffffc
+ || val <= -(offsetT) 0x100008)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("relocation overflow"));
/* FIXME: The +1 deserves a comment. */
arelent **
tc_gen_reloc (section, fixp)
- asection *section ATTRIBUTE_UNUSED;
+ asection *section;
fixS *fixp;
{
static arelent *relocs[3];
#define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
#else
#define GOT_NAME "__GLOBAL_OFFSET_TABLE_"
+#endif
+#ifdef TE_VXWORKS
+#define GOTT_BASE "__GOTT_BASE__"
+#define GOTT_INDEX "__GOTT_INDEX__"
#endif
/* This code must be parallel to the OBJ_ELF tc_fix_adjustable. */
code = BFD_RELOC_SPARC_WPLT30;
break;
case BFD_RELOC_HI22:
- if (fixp->fx_addsy != NULL
- && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
- code = BFD_RELOC_SPARC_PC22;
- else
- code = BFD_RELOC_SPARC_GOT22;
+ code = BFD_RELOC_SPARC_GOT22;
+ if (fixp->fx_addsy != NULL)
+ {
+ if (strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
+ code = BFD_RELOC_SPARC_PC22;
+#ifdef TE_VXWORKS
+ if (strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_BASE) == 0
+ || strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_INDEX) == 0)
+ code = BFD_RELOC_HI22; /* Unchanged. */
+#endif
+ }
break;
case BFD_RELOC_LO10:
- if (fixp->fx_addsy != NULL
- && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
- code = BFD_RELOC_SPARC_PC10;
- else
- code = BFD_RELOC_SPARC_GOT10;
+ code = BFD_RELOC_SPARC_GOT10;
+ if (fixp->fx_addsy != NULL)
+ {
+ if (strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0)
+ code = BFD_RELOC_SPARC_PC10;
+#ifdef TE_VXWORKS
+ if (strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_BASE) == 0
+ || strcmp (S_GET_NAME (fixp->fx_addsy), GOTT_INDEX) == 0)
+ code = BFD_RELOC_LO10; /* Unchanged. */
+#endif
+ }
break;
case BFD_RELOC_SPARC13:
code = BFD_RELOC_SPARC_GOT13;
}
#endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */
+ /* Nothing is aligned in DWARF debugging sections. */
+ if (bfd_get_section_flags (stdoutput, section) & SEC_DEBUGGING)
+ switch (code)
+ {
+ case BFD_RELOC_16: code = BFD_RELOC_SPARC_UA16; break;
+ case BFD_RELOC_32: code = BFD_RELOC_SPARC_UA32; break;
+ case BFD_RELOC_64: code = BFD_RELOC_SPARC_UA64; break;
+ default: break;
+ }
+
if (code == BFD_RELOC_SPARC_OLO10)
reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO10);
else
goto allocate_common;
}
-#ifdef BFD_ASSEMBLER
symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
-#endif
demand_empty_rest_of_line ();
return;
}
int
-sparc_regname_to_dw2regnum (const char *regname)
+sparc_regname_to_dw2regnum (char *regname)
{
char *p, *q;