/* tc-cris.c -- Assembler code for the CRIS CPU core.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright 2000 Free Software Foundation, Inc.
Contributed by Axis Communications AB, Lund, Sweden.
Originally written for GAS 1.38.1 by Mikael Asker.
#include "as.h"
#include "subsegs.h"
#include "opcode/cris.h"
+#include "dwarf2dbg.h"
/* Conventions used here:
Generally speaking, pointers to binutils types such as "fragS" and
that could clash with a current or future binutils or GAS function get
a "cris_" prefix. */
+#define SYNTAX_RELAX_REG_PREFIX "no_register_prefix"
+#define SYNTAX_ENFORCE_REG_PREFIX "register_prefix"
+#define SYNTAX_USER_SYM_LEADING_UNDERSCORE "leading_underscore"
+#define SYNTAX_USER_SYM_NO_LEADING_UNDERSCORE "no_leading_underscore"
+#define REGISTER_PREFIX_CHAR '$'
+
/* This might be CRIS_INSN_NONE if we're assembling a prefix-insn only.
Note that some prefix-insns might be assembled as CRIS_INSN_NORMAL. */
enum cris_insn_kind
static void cris_number_to_imm PARAMS ((char *, long, int, fixS *));
static void cris_create_short_jump PARAMS ((char *, addressT, addressT,
fragS *, symbolS *));
+static void s_syntax PARAMS ((int));
+static void s_cris_file PARAMS ((int));
+static void s_cris_loc PARAMS ((int));
+
+/* All the .syntax functions. */
+static void cris_force_reg_prefix PARAMS ((void));
+static void cris_relax_reg_prefix PARAMS ((void));
+static void cris_sym_leading_underscore PARAMS ((void));
+static void cris_sym_no_leading_underscore PARAMS ((void));
+
/* Handle to the opcode hash table. */
static struct hash_control *op_hash = NULL;
+/* Whether we demand that registers have a `$' prefix. Default here. */
+static boolean demand_register_prefix = false;
+
+/* Whether global user symbols have a leading underscore. Default here. */
+static boolean symbols_have_leading_underscore = true;
+
const pseudo_typeS md_pseudo_table[] =
{
{"dword", cons, 4},
+ {"syntax", s_syntax, 0},
+ {"file", s_cris_file, 0},
+ {"loc", s_cris_loc, 0},
{NULL, 0, 0}
};
in 2.9.1 and CVS of 2000-02-16. */
struct option md_longopts[] =
{
+#define OPTION_NO_US (OPTION_MD_BASE + 0)
+ {"no-underscore", no_argument, NULL, OPTION_NO_US},
+#define OPTION_US (OPTION_MD_BASE + 1)
+ {"underscore", no_argument, NULL, OPTION_US},
{NULL, no_argument, NULL, 0}
};
const int md_short_jump_size = 6;
const int md_long_jump_size = 6;
-/* Report output format. */
+/* Report output format. Small changes in output format (like elf
+ variants below) can happen until all options are parsed. */
const char *
cris_target_format ()
return "a.out-cris";
case bfd_target_elf_flavour:
+ if (symbols_have_leading_underscore)
+ return "elf32-us-cris";
return "elf32-cris";
default:
/* Modify the byte-offset BDAP into a word or dword offset
BDAP. Or really, a BDAP rX,8bit into a
- BDAP.[wd] rX,[PC+] followed by a and a word or dword. */
+ BDAP.[wd] rX,[PC+] followed by a word or dword. */
(fragP->fr_opcode)[0] = BDAP_PC_LOW + pow2_of_size * 16;
/* Keep the register number in the highest four bits. */
struct cris_prefix prefix;
char *opcodep;
char *p;
+ int insn_size = 0;
know (str);
case PREFIX_BDAP:
case PREFIX_BIAP:
case PREFIX_DIP:
+ insn_size += 2;
opcodep = frag_more (2);
/* Output the prefix opcode. */
if (prefix.reloc != BFD_RELOC_NONE)
{
/* Output an absolute mode address. */
+ insn_size += 4;
p = frag_more (4);
fix_new_exp (frag_now, (p - frag_now->fr_literal), 4,
&prefix.expr, 0, prefix.reloc);
break;
case PREFIX_PUSH:
+ insn_size += 2;
opcodep = frag_more (2);
/* Output the prefix opcode. Being a "push", we add the negative
return;
/* Done with the prefix. Continue with the main instruction. */
+ insn_size += 2;
opcodep = frag_more (2);
/* Output the instruction opcode. */
This means it is a branch to a known symbol in another
section. Code in data? Weird but valid. Emit a 32-bit
branch. */
+ insn_size += 10;
gen_cond_branch_32 (opcodep, frag_more (10), frag_now,
output_instruction.expr.X_add_symbol,
(symbolS *) NULL,
BAD_CASE (output_instruction.imm_oprnd_size);
}
+ insn_size += output_instruction.imm_oprnd_size;
p = frag_more (output_instruction.imm_oprnd_size);
fix_new_exp (frag_now, (p - frag_now->fr_literal),
output_instruction.imm_oprnd_size,
output_instruction.reloc);
}
}
+
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ dwarf2_emit_insn (insn_size);
}
/* Low level text-to-bits assembly. */
prefix.
The difference to 's' is that this does not allow an
- "immediate" expression. */
+ "immediate" expression. */
if (! get_autoinc_prefix_or_indir_op (&s, prefixp,
&mode, ®no,
&imm_expr_found,
}
}
-/* Get a general register from the string pointed out by *cPP. The
+/* Get a general register from the string pointed out by *cPP. The
variable *cPP is advanced to the character following the general
register name on a successful return, and has its initial position
otherwise.
char *oldp;
oldp = *cPP;
+ /* Handle a sometimes-mandatory dollar sign as register prefix. */
+ if (**cPP == REGISTER_PREFIX_CHAR)
+ (*cPP)++;
+ else if (demand_register_prefix)
+ return 0;
+
switch (**cPP)
{
case 'P':
{
char *s1;
const char *s2;
+ char *name_begin = *cPP;
const struct cris_spec_reg *sregp;
+ /* Handle a sometimes-mandatory dollar sign as register prefix. */
+ if (*name_begin == REGISTER_PREFIX_CHAR)
+ name_begin++;
+ else if (demand_register_prefix)
+ return 0;
+
/* Loop over all special registers. */
for (sregp = cris_spec_regs; sregp->name != NULL; sregp++)
{
/* Start over from beginning of the supposed name. */
- s1 = *cPP;
+ s1 = name_begin;
s2 = sregp->name;
while (*s2 != '\0'
| prefixp->base_reg_number /* << 0 */
| (index_reg_number << 12));
- /* */
+ /* Consume the ".S". */
if (! get_bwd_size_modifier (cPP, &size_bits))
/* Missing size, so fail. */
return 0;
&& !S_IS_DEFINED (fixP->fx_addsy)
&& !S_IS_WEAK (fixP->fx_addsy))
S_SET_WEAK (fixP->fx_addsy);
- /* FALLTHROUGH. */
+ /* Fall through. */
+
case BFD_RELOC_VTABLE_ENTRY:
- /* FIXME: I'm not sure why we do this (as does other ports), but it
- might be that this relocation can only be finished at link time. */
fixP->fx_done = 0;
break;
{
case 'H':
case 'h':
+ printf (_("Please use --help to see usage and options for this assembler.\n"));
md_show_usage (stdout);
- /* Don't continue. */
- exit (0);
+ exit (EXIT_SUCCESS);
case 'N':
warn_for_branch_expansion = 1;
return 1;
+ case OPTION_NO_US:
+ demand_register_prefix = true;
+
+ if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
+ as_bad (_("--no-underscore is invalid with a.out format"), arg);
+ else
+ symbols_have_leading_underscore = false;
+ return 1;
+
+ case OPTION_US:
+ demand_register_prefix = false;
+ symbols_have_leading_underscore = true;
+ return 1;
+
default:
return 0;
}
md_show_usage (stream)
FILE *stream;
{
- fprintf (stream, _("\n-- GNU as for CRIS\n"));
- fprintf (stream, "\n");
- fprintf (stream,
- _("*** Usage: as-cris [switches] [-o objectfile] [files...]\n"));
- fprintf (stream, _("Target-specific switches:\n"));
- fprintf (stream, _(" -h, -H : Don't execute, print this help text.\n"));
- fprintf (stream,
- _(" -N : Warn when branches are expanded to jumps.\n\n"));
- fprintf (stream, _("Use as-cris --help to see more options.\n"));
- fprintf (stream, _("objectfile : Output file in the a.out format %s"),
- _("described in the users manual.\n"));
- fprintf (stream, _(" Default output file is \"a.out\".\n"));
- fprintf (stream, _("files ... : Input files in the source format %s"),
- _(" described in the users manual.\n"));
- fprintf (stream, _(" Default input file is standard input.\n"));
- fprintf (stream, _("Description : Assembler for the CRIS processor.\n"));
+ fprintf (stream, _("CRIS-specific options:\n"));
+ fprintf (stream, "%s",
+ _(" -h, -H Don't execute, print this help text. Deprecated.\n"));
+ fprintf (stream, "%s",
+ _(" -N Warn when branches are expanded to jumps.\n"));
+ fprintf (stream, "%s",
+ _(" --underscore User symbols are normally prepended with underscore.\n"));
+ fprintf (stream, "%s",
+ _(" Registers will not need any prefix.\n"));
+ fprintf (stream, "%s",
+ _(" --no-underscore User symbols do not have any prefix.\n"));
+ fprintf (stream, "%s",
+ _(" Registers will require a `$'-prefix.\n"));
}
/* Apply a fixS (fixup of an instruction or data that we didn't have
(long) new_offset);
}
+/* Make a leading REGISTER_PREFIX_CHAR mandatory for all registers. */
+
+static void cris_force_reg_prefix ()
+{
+ demand_register_prefix = true;
+}
+
+/* Do not demand a leading REGISTER_PREFIX_CHAR for all registers. */
+
+static void cris_relax_reg_prefix ()
+{
+ demand_register_prefix = false;
+}
+
+/* Adjust for having a leading '_' on all user symbols. */
+
+static void cris_sym_leading_underscore ()
+{
+ /* We can't really do anything more than assert that what the program
+ thinks symbol starts with agrees with the command-line options, since
+ the bfd is already created. */
+
+ if (symbols_have_leading_underscore == false)
+ as_bad (".syntax %s requires command-line option `--underscore'",
+ SYNTAX_USER_SYM_LEADING_UNDERSCORE);
+}
+
+/* Adjust for not having any particular prefix on user symbols. */
+
+static void cris_sym_no_leading_underscore ()
+{
+ if (symbols_have_leading_underscore == true)
+ as_bad (".syntax %s requires command-line option `--no-underscore'",
+ SYNTAX_USER_SYM_NO_LEADING_UNDERSCORE);
+}
+
+/* Handle the .syntax pseudo, which takes an argument that decides what
+ syntax the assembly code has. */
+
+static void
+s_syntax (ignore)
+ int ignore ATTRIBUTE_UNUSED;
+{
+ static const struct syntaxes
+ {
+ const char *operand;
+ void (*fn) PARAMS ((void));
+ } syntax_table[] =
+ {{SYNTAX_ENFORCE_REG_PREFIX, cris_force_reg_prefix},
+ {SYNTAX_RELAX_REG_PREFIX, cris_relax_reg_prefix},
+ {SYNTAX_USER_SYM_LEADING_UNDERSCORE, cris_sym_leading_underscore},
+ {SYNTAX_USER_SYM_NO_LEADING_UNDERSCORE, cris_sym_no_leading_underscore}};
+
+ const struct syntaxes *sp;
+
+ for (sp = syntax_table;
+ sp < syntax_table + sizeof (syntax_table) / sizeof (syntax_table[0]);
+ sp++)
+ {
+ if (strncmp (input_line_pointer, sp->operand,
+ strlen (sp->operand)) == 0)
+ {
+ (sp->fn) ();
+
+ input_line_pointer += strlen (sp->operand);
+ demand_empty_rest_of_line ();
+ return;
+ }
+ }
+
+ as_bad (_("Unknown .syntax operand"));
+}
+
+/* Wrapper for dwarf2_directive_file to emit error if this is seen when
+ not emitting ELF. */
+
+static void
+s_cris_file (dummy)
+ int dummy;
+{
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+ as_bad ("Pseudodirective .file is only valid when generating ELF");
+ else
+ dwarf2_directive_file (dummy);
+}
+
+/* Wrapper for dwarf2_directive_loc to emit error if this is seen when not
+ emitting ELF. */
+
+static void
+s_cris_loc (dummy)
+ int dummy;
+{
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+ as_bad ("Pseudodirective .loc is only valid when generating ELF");
+ else
+ dwarf2_directive_loc (dummy);
+}
+
/*
* Local variables:
* eval: (c-set-style "gnu")