summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/gas/config/tc-cris.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.25/gas/config/tc-cris.c')
-rw-r--r--binutils-2.25/gas/config/tc-cris.c4407
1 files changed, 4407 insertions, 0 deletions
diff --git a/binutils-2.25/gas/config/tc-cris.c b/binutils-2.25/gas/config/tc-cris.c
new file mode 100644
index 00000000..657c7ede
--- /dev/null
+++ b/binutils-2.25/gas/config/tc-cris.c
@@ -0,0 +1,4407 @@
+/* tc-cris.c -- Assembler code for the CRIS CPU core.
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
+
+ Contributed by Axis Communications AB, Lund, Sweden.
+ Originally written for GAS 1.38.1 by Mikael Asker.
+ Updates, BFDizing, GNUifying and ELF support by Hans-Peter Nilsson.
+
+ 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 3, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "as.h"
+#include "safe-ctype.h"
+#include "subsegs.h"
+#include "opcode/cris.h"
+#include "dwarf2dbg.h"
+
+/* Conventions used here:
+ Generally speaking, pointers to binutils types such as "fragS" and
+ "expressionS" get parameter and variable names ending in "P", such as
+ "fragP", to harmonize with the rest of the binutils code. Other
+ pointers get a "p" suffix, such as "bufp". Any function or type-name
+ 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 '$'
+
+/* True for expressions where getting X_add_symbol and X_add_number is
+ enough to get the "base" and "offset"; no need to make_expr_symbol.
+ It's not enough to check if X_op_symbol is NULL; that misses unary
+ operations like O_uminus. */
+#define SIMPLE_EXPR(EXP) \
+ ((EXP)->X_op == O_constant || (EXP)->X_op == O_symbol)
+
+/* Like in ":GOT", ":GOTOFF" etc. Other ports use '@', but that's in
+ line_separator_chars for CRIS, so we avoid it. */
+#define RELOC_SUFFIX_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
+{
+ CRIS_INSN_NORMAL, CRIS_INSN_NONE, CRIS_INSN_BRANCH, CRIS_INSN_MUL
+};
+
+/* An instruction will have one of these prefixes.
+ Although the same bit-pattern, we handle BDAP with an immediate
+ expression (eventually quick or [pc+]) different from when we only have
+ register expressions. */
+enum prefix_kind
+{
+ PREFIX_NONE, PREFIX_BDAP_IMM, PREFIX_BDAP, PREFIX_BIAP, PREFIX_DIP,
+ PREFIX_PUSH
+};
+
+/* The prefix for an instruction. */
+struct cris_prefix
+{
+ enum prefix_kind kind;
+ int base_reg_number;
+ unsigned int opcode;
+
+ /* There might be an expression to be evaluated, like I in [rN+I]. */
+ expressionS expr;
+
+ /* If there's an expression, we might need a relocation. Here's the
+ type of what relocation to start relaxaton with.
+ The relocation is assumed to start immediately after the prefix insn,
+ so we don't provide an offset. */
+ enum bfd_reloc_code_real reloc;
+};
+
+/* The description of the instruction being assembled. */
+struct cris_instruction
+{
+ /* If CRIS_INSN_NONE, then this insn is of zero length. */
+ enum cris_insn_kind insn_type;
+
+ /* If a special register was mentioned, this is its description, else
+ it is NULL. */
+ const struct cris_spec_reg *spec_reg;
+
+ unsigned int opcode;
+
+ /* An insn may have at most one expression; theoretically there could be
+ another in its prefix (but I don't see how that could happen). */
+ expressionS expr;
+
+ /* The expression might need a relocation. Here's one to start
+ relaxation with. */
+ enum bfd_reloc_code_real reloc;
+
+ /* The size in bytes of an immediate expression, or zero if
+ nonapplicable. */
+ int imm_oprnd_size;
+};
+
+enum cris_archs
+{
+ arch_cris_unknown,
+ arch_crisv0, arch_crisv3, arch_crisv8, arch_crisv10,
+ arch_cris_any_v0_v10, arch_crisv32, arch_cris_common_v10_v32
+};
+
+static enum cris_archs cris_arch_from_string (char **);
+static int cris_insn_ver_valid_for_arch (enum cris_insn_version_usage,
+ enum cris_archs);
+
+static void cris_process_instruction (char *, struct cris_instruction *,
+ struct cris_prefix *);
+static int get_bwd_size_modifier (char **, int *);
+static int get_bw_size_modifier (char **, int *);
+static int get_gen_reg (char **, int *);
+static int get_spec_reg (char **, const struct cris_spec_reg **);
+static int get_sup_reg (char **, int *);
+static int get_autoinc_prefix_or_indir_op (char **, struct cris_prefix *,
+ int *, int *, int *,
+ expressionS *);
+static int get_3op_or_dip_prefix_op (char **, struct cris_prefix *);
+static int cris_get_expression (char **, expressionS *);
+static int get_flags (char **, int *);
+static void gen_bdap (int, expressionS *);
+static int branch_disp (int);
+static void gen_cond_branch_32 (char *, char *, fragS *, symbolS *, symbolS *,
+ long int);
+static void cris_number_to_imm (char *, long, int, fixS *, segT);
+static void s_syntax (int);
+static void s_cris_file (int);
+static void s_cris_loc (int);
+static void s_cris_arch (int);
+static void s_cris_dtpoff (int);
+
+/* Get ":GOT", ":GOTOFF", ":PLT" etc. suffixes. */
+static void cris_get_reloc_suffix (char **, bfd_reloc_code_real_type *,
+ expressionS *);
+static unsigned int cris_get_specified_reloc_size (bfd_reloc_code_real_type);
+
+/* All the .syntax functions. */
+static void cris_force_reg_prefix (void);
+static void cris_relax_reg_prefix (void);
+static void cris_sym_leading_underscore (void);
+static void cris_sym_no_leading_underscore (void);
+static char *cris_insn_first_word_frag (void);
+
+/* Handle to the opcode hash table. */
+static struct hash_control *op_hash = NULL;
+
+/* If we target cris-axis-linux-gnu (as opposed to generic cris-axis-elf),
+ we default to no underscore and required register-prefixes. The
+ difference is in the default values. */
+#ifdef TE_LINUX
+#define DEFAULT_CRIS_AXIS_LINUX_GNU TRUE
+#else
+#define DEFAULT_CRIS_AXIS_LINUX_GNU FALSE
+#endif
+
+/* Whether we demand that registers have a `$' prefix. Default here. */
+static bfd_boolean demand_register_prefix = DEFAULT_CRIS_AXIS_LINUX_GNU;
+
+/* Whether global user symbols have a leading underscore. Default here. */
+static bfd_boolean symbols_have_leading_underscore
+ = !DEFAULT_CRIS_AXIS_LINUX_GNU;
+
+/* Whether or not we allow PIC, and expand to PIC-friendly constructs. */
+static bfd_boolean pic = FALSE;
+
+/* Whether or not we allow TLS suffixes. For the moment, we always do. */
+static const bfd_boolean tls = TRUE;
+
+/* If we're configured for "cris", default to allow all v0..v10
+ instructions and register names. */
+#ifndef DEFAULT_CRIS_ARCH
+#define DEFAULT_CRIS_ARCH cris_any_v0_v10
+#endif
+
+/* No whitespace in the CONCAT2 parameter list. */
+static enum cris_archs cris_arch = XCONCAT2 (arch_,DEFAULT_CRIS_ARCH);
+
+const pseudo_typeS md_pseudo_table[] =
+{
+ {"dword", cons, 4},
+ {"dtpoffd", s_cris_dtpoff, 4},
+ {"syntax", s_syntax, 0},
+ {"file", s_cris_file, 0},
+ {"loc", s_cris_loc, 0},
+ {"arch", s_cris_arch, 0},
+ {NULL, 0, 0}
+};
+
+static int warn_for_branch_expansion = 0;
+
+/* Whether to emit error when a MULS/MULU could be located last on a
+ cache-line. */
+static int err_for_dangerous_mul_placement
+ = (XCONCAT2 (arch_,DEFAULT_CRIS_ARCH) != arch_crisv32);
+
+const char cris_comment_chars[] = ";";
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output. */
+/* Note that input_file.c hand-checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that slash-star will always start a comment. */
+const char line_comment_chars[] = "#";
+const char line_separator_chars[] = "@";
+
+/* Now all floating point support is shut off. See md_atof. */
+const char EXP_CHARS[] = "";
+const char FLT_CHARS[] = "";
+
+/* For CRIS, we encode the relax_substateTs (in e.g. fr_substate) as:
+ 2 1 0
+ ---/ /--+-----------------+-----------------+-----------------+
+ | what state ? | how long ? |
+ ---/ /--+-----------------+-----------------+-----------------+
+
+ The "how long" bits are 00 = byte, 01 = word, 10 = dword (long).
+ Not all lengths are legit for a given value of (what state).
+
+ Groups for CRIS address relaxing:
+
+ 1. Bcc (pre-V32)
+ length: byte, word, 10-byte expansion
+
+ 2. BDAP
+ length: byte, word, dword
+
+ 3. MULS/MULU
+ Not really a relaxation (no infrastructure to get delay-slots
+ right), just an alignment and placement checker for the v10
+ multiply/cache-bug.
+
+ 4. Bcc (V32 and later)
+ length: byte, word, 14-byte expansion
+
+ 5. Bcc (V10+V32)
+ length: byte, word, error
+
+ 6. BA (V32)
+ length: byte, word, dword
+
+ 7. LAPC (V32)
+ length: byte, dword
+ */
+
+#define STATE_COND_BRANCH (1)
+#define STATE_BASE_PLUS_DISP_PREFIX (2)
+#define STATE_MUL (3)
+#define STATE_COND_BRANCH_V32 (4)
+#define STATE_COND_BRANCH_COMMON (5)
+#define STATE_ABS_BRANCH_V32 (6)
+#define STATE_LAPC (7)
+#define STATE_COND_BRANCH_PIC (8)
+
+#define STATE_LENGTH_MASK (3)
+#define STATE_BYTE (0)
+#define STATE_WORD (1)
+#define STATE_DWORD (2)
+/* Symbol undefined. */
+#define STATE_UNDF (3)
+#define STATE_MAX_LENGTH (3)
+
+/* These displacements are relative to the address following the opcode
+ word of the instruction. The first letter is Byte, Word. The 2nd
+ letter is Forward, Backward. */
+
+#define BRANCH_BF ( 254)
+#define BRANCH_BB (-256)
+#define BRANCH_BF_V32 ( 252)
+#define BRANCH_BB_V32 (-258)
+#define BRANCH_WF (2 + 32767)
+#define BRANCH_WB (2 + -32768)
+#define BRANCH_WF_V32 (-2 + 32767)
+#define BRANCH_WB_V32 (-2 + -32768)
+
+#define BDAP_BF ( 127)
+#define BDAP_BB (-128)
+#define BDAP_WF ( 32767)
+#define BDAP_WB (-32768)
+
+#define ENCODE_RELAX(what, length) (((what) << 2) + (length))
+
+const relax_typeS md_cris_relax_table[] =
+{
+ /* Error sentinel (0, 0). */
+ {1, 1, 0, 0},
+
+ /* Unused (0, 1). */
+ {1, 1, 0, 0},
+
+ /* Unused (0, 2). */
+ {1, 1, 0, 0},
+
+ /* Unused (0, 3). */
+ {1, 1, 0, 0},
+
+ /* Bcc o (1, 0). */
+ {BRANCH_BF, BRANCH_BB, 0, ENCODE_RELAX (1, 1)},
+
+ /* Bcc [PC+] (1, 1). */
+ {BRANCH_WF, BRANCH_WB, 2, ENCODE_RELAX (1, 2)},
+
+ /* BEXT/BWF, BA, JUMP (external), JUMP (always), Bnot_cc, JUMP (default)
+ (1, 2). */
+ {0, 0, 10, 0},
+
+ /* Unused (1, 3). */
+ {1, 1, 0, 0},
+
+ /* BDAP o (2, 0). */
+ {BDAP_BF, BDAP_BB, 0, ENCODE_RELAX (2, 1)},
+
+ /* BDAP.[bw] [PC+] (2, 1). */
+ {BDAP_WF, BDAP_WB, 2, ENCODE_RELAX (2, 2)},
+
+ /* BDAP.d [PC+] (2, 2). */
+ {0, 0, 4, 0},
+
+ /* Unused (2, 3). */
+ {1, 1, 0, 0},
+
+ /* MULS/MULU (3, 0). Positions (3, 1..3) are unused. */
+ {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
+
+ /* V32: Bcc o (4, 0). */
+ {BRANCH_BF_V32, BRANCH_BB_V32, 0, ENCODE_RELAX (4, 1)},
+
+ /* V32: Bcc [PC+] (4, 1). */
+ {BRANCH_WF_V32, BRANCH_WB_V32, 2, ENCODE_RELAX (4, 2)},
+
+ /* V32: BA .+12; NOP; BA32 target; NOP; Bcc .-6 (4, 2). */
+ {0, 0, 12, 0},
+
+ /* Unused (4, 3). */
+ {1, 1, 0, 0},
+
+ /* COMMON: Bcc o (5, 0). The offsets are calculated as for v32. Code
+ should contain two nop insns (or four if offset size is large or
+ unknown) after every label. */
+ {BRANCH_BF_V32, BRANCH_BB_V32, 0, ENCODE_RELAX (5, 1)},
+
+ /* COMMON: Bcc [PC+] (5, 1). */
+ {BRANCH_WF_V32, BRANCH_WB_V32, 2, ENCODE_RELAX (5, 2)},
+
+ /* COMMON: FIXME: ???. Treat as error currently. */
+ {0, 0, 12, 0},
+
+ /* Unused (5, 3). */
+ {1, 1, 0, 0},
+
+ /* V32: BA o (6, 0). */
+ {BRANCH_BF_V32, BRANCH_BB_V32, 0, ENCODE_RELAX (6, 1)},
+
+ /* V32: BA.W (6, 1). */
+ {BRANCH_WF_V32, BRANCH_WB_V32, 2, ENCODE_RELAX (6, 2)},
+
+ /* V32: BA.D (6, 2). */
+ {0, 0, 4, 0},
+
+ /* Unused (6, 3). */
+ {1, 1, 0, 0},
+
+ /* LAPC: LAPCQ .+0..15*2,Rn (7, 0). */
+ {14*2, -1*2, 0, ENCODE_RELAX (7, 2)},
+
+ /* Unused (7, 1).
+ While there's a shorter sequence, e.g. LAPCQ + an ADDQ or SUBQ,
+ that would affect flags, so we can't do that as it wouldn't be a
+ proper insn expansion of LAPCQ. This row is associated with a
+ 2-byte expansion, so it's unused rather than the next. */
+ {1, 1, 0, 0},
+
+ /* LAPC: LAPC.D (7, 2). */
+ {0, 0, 4, 0},
+
+ /* Unused (7, 3). */
+ {1, 1, 0, 0},
+
+ /* PIC for pre-v32: Bcc o (8, 0). */
+ {BRANCH_BF, BRANCH_BB, 0, ENCODE_RELAX (STATE_COND_BRANCH_PIC, 1)},
+
+ /* Bcc [PC+] (8, 1). */
+ {BRANCH_WF, BRANCH_WB, 2, ENCODE_RELAX (STATE_COND_BRANCH_PIC, 2)},
+
+ /* 32-bit expansion, PIC (8, 2). */
+ {0, 0, 12, 0},
+
+ /* Unused (8, 3). */
+ {1, 1, 0, 0}
+};
+
+#undef BDAP_BF
+#undef BDAP_BB
+#undef BDAP_WF
+#undef BDAP_WB
+
+/* Target-specific multicharacter options, not const-declared. */
+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},
+#define OPTION_PIC (OPTION_US + 1)
+ {"pic", no_argument, NULL, OPTION_PIC},
+#define OPTION_MULBUG_ABORT_ON (OPTION_PIC + 1)
+ {"mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_ON},
+#define OPTION_MULBUG_ABORT_OFF (OPTION_MULBUG_ABORT_ON + 1)
+ {"no-mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_OFF},
+#define OPTION_ARCH (OPTION_MULBUG_ABORT_OFF + 1)
+ {"march", required_argument, NULL, OPTION_ARCH},
+ {NULL, no_argument, NULL, 0}
+};
+
+/* Not const-declared. */
+size_t md_longopts_size = sizeof (md_longopts);
+const char *md_shortopts = "hHN";
+
+/* At first glance, this may seems wrong and should be 4 (ba + nop); but
+ since a short_jump must skip a *number* of long jumps, it must also be
+ a long jump. Here, we hope to make it a "ba [16bit_offs]" and a "nop"
+ for the delay slot and hope that the jump table at most needs
+ 32767/4=8191 long-jumps. A branch is better than a jump, since it is
+ relative; we will not have a reloc to fix up somewhere.
+
+ Note that we can't add relocs, because relaxation uses these fixed
+ numbers, and md_create_short_jump is called after relaxation. */
+
+int md_short_jump_size = 6;
+
+/* The v32 version has a delay-slot, hence two bytes longer.
+ The pre-v32 PIC version uses a prefixed insn. */
+#define cris_any_v0_v10_long_jump_size 6
+#define cris_any_v0_v10_long_jump_size_pic 8
+#define crisv32_long_jump_size 8
+
+int md_long_jump_size = XCONCAT2 (DEFAULT_CRIS_ARCH,_long_jump_size);
+
+/* Report output format. Small changes in output format (like elf
+ variants below) can happen until all options are parsed, but after
+ that, the output format must remain fixed. */
+
+const char *
+cris_target_format (void)
+{
+ switch (OUTPUT_FLAVOR)
+ {
+ case bfd_target_aout_flavour:
+ return "a.out-cris";
+
+ case bfd_target_elf_flavour:
+ if (symbols_have_leading_underscore)
+ return "elf32-us-cris";
+ return "elf32-cris";
+
+ default:
+ abort ();
+ return NULL;
+ }
+}
+
+/* Return a bfd_mach_cris... value corresponding to the value of
+ cris_arch. */
+
+unsigned int
+cris_mach (void)
+{
+ unsigned int retval = 0;
+
+ switch (cris_arch)
+ {
+ case arch_cris_common_v10_v32:
+ retval = bfd_mach_cris_v10_v32;
+ break;
+
+ case arch_crisv32:
+ retval = bfd_mach_cris_v32;
+ break;
+
+ case arch_crisv10:
+ case arch_cris_any_v0_v10:
+ retval = bfd_mach_cris_v0_v10;
+ break;
+
+ default:
+ BAD_CASE (cris_arch);
+ }
+
+ return retval;
+}
+
+/* We need a port-specific relaxation function to cope with sym2 - sym1
+ relative expressions with both symbols in the same segment (but not
+ necessarily in the same frag as this insn), for example:
+ move.d [pc+sym2-(sym1-2)],r10
+ sym1:
+ The offset can be 8, 16 or 32 bits long. */
+
+long
+cris_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS *fragP,
+ long stretch ATTRIBUTE_UNUSED)
+{
+ long growth;
+ offsetT aim = 0;
+ symbolS *symbolP;
+ const relax_typeS *this_type;
+ const relax_typeS *start_type;
+ relax_substateT next_state;
+ relax_substateT this_state;
+ const relax_typeS *table = TC_GENERIC_RELAX_TABLE;
+
+ /* We only have to cope with frags as prepared by
+ md_estimate_size_before_relax. The dword cases may get here
+ because of the different reasons that they aren't relaxable. */
+ switch (fragP->fr_subtype)
+ {
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
+ /* When we get to these states, the frag won't grow any more. */
+ return 0;
+
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_WORD):
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
+ if (fragP->fr_symbol == NULL
+ || S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+ as_fatal (_("internal inconsistency problem in %s: fr_symbol %lx"),
+ __FUNCTION__, (long) fragP->fr_symbol);
+ symbolP = fragP->fr_symbol;
+ if (symbol_resolved_p (symbolP))
+ as_fatal (_("internal inconsistency problem in %s: resolved symbol"),
+ __FUNCTION__);
+ aim = S_GET_VALUE (symbolP);
+ break;
+
+ case ENCODE_RELAX (STATE_MUL, STATE_BYTE):
+ /* Nothing to do here. */
+ return 0;
+
+ default:
+ as_fatal (_("internal inconsistency problem in %s: fr_subtype %d"),
+ __FUNCTION__, fragP->fr_subtype);
+ }
+
+ /* The rest is stolen from relax_frag. There's no obvious way to
+ share the code, but fortunately no requirement to keep in sync as
+ long as fragP->fr_symbol does not have its segment changed. */
+
+ this_state = fragP->fr_subtype;
+ start_type = this_type = table + this_state;
+
+ if (aim < 0)
+ {
+ /* Look backwards. */
+ for (next_state = this_type->rlx_more; next_state;)
+ if (aim >= this_type->rlx_backward)
+ next_state = 0;
+ else
+ {
+ /* Grow to next state. */
+ this_state = next_state;
+ this_type = table + this_state;
+ next_state = this_type->rlx_more;
+ }
+ }
+ else
+ {
+ /* Look forwards. */
+ for (next_state = this_type->rlx_more; next_state;)
+ if (aim <= this_type->rlx_forward)
+ next_state = 0;
+ else
+ {
+ /* Grow to next state. */
+ this_state = next_state;
+ this_type = table + this_state;
+ next_state = this_type->rlx_more;
+ }
+ }
+
+ growth = this_type->rlx_length - start_type->rlx_length;
+ if (growth != 0)
+ fragP->fr_subtype = this_state;
+ return growth;
+}
+
+/* Prepare machine-dependent frags for relaxation.
+
+ Called just before relaxation starts. Any symbol that is now undefined
+ will not become defined.
+
+ Return the correct fr_subtype in the frag.
+
+ Return the initial "guess for fr_var" to caller. The guess for fr_var
+ is *actually* the growth beyond fr_fix. Whatever we do to grow fr_fix
+ or fr_var contributes to our returned value.
+
+ Although it may not be explicit in the frag, pretend
+ fr_var starts with a value. */
+
+int
+md_estimate_size_before_relax (fragS *fragP, segT segment_type)
+{
+ int old_fr_fix;
+ symbolS *symbolP = fragP->fr_symbol;
+
+#define HANDLE_RELAXABLE(state) \
+ case ENCODE_RELAX (state, STATE_UNDF): \
+ if (symbolP != NULL \
+ && S_GET_SEGMENT (symbolP) == segment_type \
+ && !S_IS_WEAK (symbolP)) \
+ /* The symbol lies in the same segment - a relaxable \
+ case. */ \
+ fragP->fr_subtype \
+ = ENCODE_RELAX (state, STATE_BYTE); \
+ else \
+ /* Unknown or not the same segment, so not relaxable. */ \
+ fragP->fr_subtype \
+ = ENCODE_RELAX (state, STATE_DWORD); \
+ fragP->fr_var \
+ = md_cris_relax_table[fragP->fr_subtype].rlx_length; \
+ break
+
+ old_fr_fix = fragP->fr_fix;
+
+ switch (fragP->fr_subtype)
+ {
+ HANDLE_RELAXABLE (STATE_COND_BRANCH);
+ HANDLE_RELAXABLE (STATE_COND_BRANCH_V32);
+ HANDLE_RELAXABLE (STATE_COND_BRANCH_COMMON);
+ HANDLE_RELAXABLE (STATE_COND_BRANCH_PIC);
+ HANDLE_RELAXABLE (STATE_ABS_BRANCH_V32);
+
+ case ENCODE_RELAX (STATE_LAPC, STATE_UNDF):
+ if (symbolP != NULL
+ && S_GET_SEGMENT (symbolP) == segment_type
+ && !S_IS_WEAK (symbolP))
+ {
+ /* The symbol lies in the same segment - a relaxable case.
+ Check if we currently have an odd offset; we can't code
+ that into the instruction. Relaxing presumably only cause
+ multiple-of-two changes, so we should only need to adjust
+ for that here. */
+ bfd_vma target_address
+ = (symbolP
+ ? S_GET_VALUE (symbolP)
+ : 0) + fragP->fr_offset;
+ bfd_vma var_part_offset = fragP->fr_fix;
+ bfd_vma address_of_var_part = fragP->fr_address + var_part_offset;
+ long offset = target_address - (address_of_var_part - 2);
+
+ fragP->fr_subtype
+ = (offset & 1)
+ ? ENCODE_RELAX (STATE_LAPC, STATE_DWORD)
+ : ENCODE_RELAX (STATE_LAPC, STATE_BYTE);
+ }
+ else
+ /* Unknown or not the same segment, so not relaxable. */
+ fragP->fr_subtype
+ = ENCODE_RELAX (STATE_LAPC, STATE_DWORD);
+ fragP->fr_var
+ = md_cris_relax_table[fragP->fr_subtype].rlx_length;
+ break;
+
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_UNDF):
+ /* Note that we can not do anything sane with relaxing
+ [rX + a_known_symbol_in_text], it will have to be a 32-bit
+ value.
+
+ We could play tricks with managing a constant pool and make
+ a_known_symbol_in_text a "bdap [pc + offset]" pointing there
+ (like the GOT for ELF shared libraries), but that's no use, it
+ would in general be no shorter or faster code, only more
+ complicated. */
+
+ if (S_GET_SEGMENT (symbolP) != absolute_section)
+ {
+ /* Go for dword if not absolute or same segment. */
+ fragP->fr_subtype
+ = ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD);
+ fragP->fr_var = md_cris_relax_table[fragP->fr_subtype].rlx_length;
+ }
+ else if (!symbol_resolved_p (fragP->fr_symbol))
+ {
+ /* The symbol will eventually be completely resolved as an
+ absolute expression, but right now it depends on the result
+ of relaxation and we don't know anything else about the
+ value. We start relaxation with the assumption that it'll
+ fit in a byte. */
+ fragP->fr_subtype
+ = ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE);
+ fragP->fr_var = md_cris_relax_table[fragP->fr_subtype].rlx_length;
+ }
+ else
+ {
+ /* Absolute expression. */
+ long int value;
+ value = (symbolP != NULL
+ ? S_GET_VALUE (symbolP) : 0) + fragP->fr_offset;
+
+ if (value >= -128 && value <= 127)
+ {
+ /* Byte displacement. */
+ (fragP->fr_opcode)[0] = value;
+ }
+ else
+ {
+ /* Word or dword displacement. */
+ int pow2_of_size = 1;
+ char *writep;
+
+ if (value < -32768 || value > 32767)
+ {
+ /* Outside word range, make it a dword. */
+ pow2_of_size = 2;
+ }
+
+ /* 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 word or dword. */
+ (fragP->fr_opcode)[0] = BDAP_PC_LOW + pow2_of_size * 16;
+
+ /* Keep the register number in the highest four bits. */
+ (fragP->fr_opcode)[1] &= 0xF0;
+ (fragP->fr_opcode)[1] |= BDAP_INCR_HIGH;
+
+ /* It grew by two or four bytes. */
+ fragP->fr_fix += 1 << pow2_of_size;
+ writep = fragP->fr_literal + old_fr_fix;
+ md_number_to_chars (writep, value, 1 << pow2_of_size);
+ }
+ frag_wane (fragP);
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_BYTE):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_WORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+ case ENCODE_RELAX (STATE_LAPC, STATE_BYTE):
+ case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_WORD):
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
+ /* When relaxing a section for the second time, we don't need to
+ do anything except making sure that fr_var is set right. */
+ fragP->fr_var = md_cris_relax_table[fragP->fr_subtype].rlx_length;
+ break;
+
+ case ENCODE_RELAX (STATE_MUL, STATE_BYTE):
+ /* Nothing to do here. */
+ break;
+
+ default:
+ BAD_CASE (fragP->fr_subtype);
+ }
+
+ return fragP->fr_var + (fragP->fr_fix - old_fr_fix);
+}
+
+/* Perform post-processing of machine-dependent frags after relaxation.
+ Called after relaxation is finished.
+ In: Address of frag.
+ fr_type == rs_machine_dependent.
+ fr_subtype is what the address relaxed to.
+
+ Out: Any fixS:s and constants are set up.
+
+ The caller will turn the frag into a ".space 0". */
+
+void
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED,
+ fragS *fragP)
+{
+ /* Pointer to first byte in variable-sized part of the frag. */
+ char *var_partp;
+
+ /* Pointer to first opcode byte in frag. */
+ char *opcodep;
+
+ /* Used to check integrity of the relaxation.
+ One of 2 = long, 1 = word, or 0 = byte. */
+ int length_code ATTRIBUTE_UNUSED;
+
+ /* Size in bytes of variable-sized part of frag. */
+ int var_part_size = 0;
+
+ /* This is part of *fragP. It contains all information about addresses
+ and offsets to varying parts. */
+ symbolS *symbolP;
+ unsigned long var_part_offset;
+
+ /* Where, in file space, is _var of *fragP? */
+ unsigned long address_of_var_part = 0;
+
+ /* Where, in file space, does addr point? */
+ unsigned long target_address;
+
+ know (fragP->fr_type == rs_machine_dependent);
+
+ length_code = fragP->fr_subtype & STATE_LENGTH_MASK;
+ know (length_code >= 0 && length_code < STATE_MAX_LENGTH);
+
+ var_part_offset = fragP->fr_fix;
+ var_partp = fragP->fr_literal + var_part_offset;
+ opcodep = fragP->fr_opcode;
+
+ symbolP = fragP->fr_symbol;
+ target_address = (symbolP ? S_GET_VALUE (symbolP) : 0) + fragP->fr_offset;
+ address_of_var_part = fragP->fr_address + var_part_offset;
+
+ switch (fragP->fr_subtype)
+ {
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_BYTE):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_BYTE):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_BYTE):
+ opcodep[0] = branch_disp ((target_address - address_of_var_part));
+ var_part_size = 0;
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_WORD):
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_WORD):
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_WORD):
+ /* We had a quick immediate branch, now turn it into a word one i.e. a
+ PC autoincrement. */
+ opcodep[0] = BRANCH_PC_LOW;
+ opcodep[1] &= 0xF0;
+ opcodep[1] |= BRANCH_INCR_HIGH;
+ md_number_to_chars (var_partp,
+ (long)
+ (target_address
+ - (address_of_var_part
+ + (cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32
+ ? -2 : 2))),
+ 2);
+ var_part_size = 2;
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+ gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
+ fragP->fr_symbol, (symbolS *) NULL,
+ fragP->fr_offset);
+ /* Ten bytes added: a branch, nop and a jump. */
+ var_part_size = 2 + 2 + 4 + 2;
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH_PIC, STATE_DWORD):
+ gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
+ fragP->fr_symbol, (symbolS *) NULL,
+ fragP->fr_offset);
+ /* Twelve bytes added: a branch, nop and a pic-branch-32. */
+ var_part_size = 2 + 2 + 4 + 2 + 2;
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+ gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
+ fragP->fr_symbol, (symbolS *) NULL,
+ fragP->fr_offset);
+ /* Twelve bytes added: a branch, nop and another branch and nop. */
+ var_part_size = 2 + 2 + 2 + 4 + 2;
+ break;
+
+ case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Relaxation to long branches for .arch common_v10_v32\
+ not implemented"));
+ /* Pretend we have twelve bytes for sake of quelling further
+ errors. */
+ var_part_size = 2 + 2 + 2 + 4 + 2;
+ break;
+
+ case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+ /* We had a quick immediate branch or a word immediate ba. Now
+ turn it into a dword one. */
+ opcodep[0] = BA_DWORD_OPCODE & 255;
+ opcodep[1] = (BA_DWORD_OPCODE >> 8) & 255;
+ fix_new (fragP, var_partp - fragP->fr_literal, 4, symbolP,
+ fragP->fr_offset + 6, 1, BFD_RELOC_32_PCREL);
+ var_part_size = 4;
+ break;
+
+ case ENCODE_RELAX (STATE_LAPC, STATE_BYTE):
+ {
+ long offset = target_address - (address_of_var_part - 2);
+
+ /* This is mostly a sanity check; useful occurrences (if there
+ really are any) should have been caught in
+ md_estimate_size_before_relax. We can (at least
+ theoretically) stumble over invalid code with odd sizes and
+ .p2aligns within the code, so emit an error if that happens.
+ (The generic relaxation machinery is not fit to check this.) */
+
+ if (offset & 1)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Complicated LAPC target operand is not\
+ a multiple of two. Use LAPC.D"));
+
+ /* FIXME: This *is* a sanity check. Remove when done with. */
+ if (offset > 15*2 || offset < 0)
+ as_fatal (_("Internal error found in md_convert_frag: offset %ld.\
+ Please report this."),
+ offset);
+
+ opcodep[0] |= (offset / 2) & 0xf;
+ var_part_size = 0;
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
+ {
+ md_number_to_chars (opcodep,
+ LAPC_DWORD_OPCODE + (opcodep[1] & 0xf0) * 256,
+ 2);
+ /* Remember that the reloc is against the position *after* the
+ relocated contents, so we need to adjust to the start of
+ the insn. */
+ fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
+ fragP->fr_offset + 6, 1, BFD_RELOC_32_PCREL);
+ var_part_size = 4;
+ }
+ break;
+
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
+ if (symbolP == NULL)
+ as_fatal (_("internal inconsistency in %s: bdapq no symbol"),
+ __FUNCTION__);
+ opcodep[0] = S_GET_VALUE (symbolP);
+ var_part_size = 0;
+ break;
+
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_WORD):
+ /* We had a BDAP 8-bit "quick immediate", now turn it into a 16-bit
+ one that uses PC autoincrement. */
+ opcodep[0] = BDAP_PC_LOW + (1 << 4);
+ opcodep[1] &= 0xF0;
+ opcodep[1] |= BDAP_INCR_HIGH;
+ if (symbolP == NULL)
+ as_fatal (_("internal inconsistency in %s: bdap.w with no symbol"),
+ __FUNCTION__);
+ md_number_to_chars (var_partp, S_GET_VALUE (symbolP), 2);
+ var_part_size = 2;
+ break;
+
+ case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
+ /* We had a BDAP 16-bit "word", change the offset to a dword. */
+ opcodep[0] = BDAP_PC_LOW + (2 << 4);
+ opcodep[1] &= 0xF0;
+ opcodep[1] |= BDAP_INCR_HIGH;
+ if (fragP->fr_symbol == NULL)
+ md_number_to_chars (var_partp, fragP->fr_offset, 4);
+ else
+ fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
+ fragP->fr_offset, 0, BFD_RELOC_32);
+ var_part_size = 4;
+ break;
+
+ case ENCODE_RELAX (STATE_MUL, STATE_BYTE):
+ /* This is the only time we check position and alignment of the
+ placement-tracking frag. */
+ if (sec->alignment_power < 2)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("section alignment must be >= 4 bytes to check MULS/MULU safeness"));
+ else
+ {
+ /* If the address after the MULS/MULU has alignment which is
+ that of the section and may be that of a cache-size of the
+ buggy versions, then the MULS/MULU can be placed badly. */
+ if ((address_of_var_part
+ & ((1 << sec->alignment_power) - 1) & 31) == 0)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("dangerous MULS/MULU location; give it higher alignment"));
+ }
+ break;
+
+ default:
+ BAD_CASE (fragP->fr_subtype);
+ break;
+ }
+
+ fragP->fr_fix += var_part_size;
+}
+
+/* Generate a short jump around a secondary jump table.
+ Also called from md_create_long_jump, when sufficient. */
+
+void
+md_create_short_jump (char *storep, addressT from_addr, addressT to_addr,
+ fragS *fragP ATTRIBUTE_UNUSED,
+ symbolS *to_symbol ATTRIBUTE_UNUSED)
+{
+ long int distance;
+
+ /* See md_create_long_jump about the comment on the "+ 2". */
+ long int max_minimal_minus_distance;
+ long int max_minimal_plus_distance;
+ long int max_minus_distance;
+ long int max_plus_distance;
+ int nop_opcode;
+
+ if (cris_arch == arch_crisv32)
+ {
+ max_minimal_minus_distance = BRANCH_BB_V32 + 2;
+ max_minimal_plus_distance = BRANCH_BF_V32 + 2;
+ max_minus_distance = BRANCH_WB_V32 + 2;
+ max_plus_distance = BRANCH_WF_V32 + 2;
+ nop_opcode = NOP_OPCODE_V32;
+ }
+ else if (cris_arch == arch_cris_common_v10_v32)
+ /* Bail out for compatibility mode. (It seems it can be implemented,
+ perhaps with a 10-byte sequence: "move.d NNNN,$pc/$acr", "jump
+ $acr", "nop"; but doesn't seem worth it at the moment.) */
+ as_fatal (_("Out-of-range .word offset handling\
+ is not implemented for .arch common_v10_v32"));
+ else
+ {
+ max_minimal_minus_distance = BRANCH_BB + 2;
+ max_minimal_plus_distance = BRANCH_BF + 2;
+ max_minus_distance = BRANCH_WB + 2;
+ max_plus_distance = BRANCH_WF + 2;
+ nop_opcode = NOP_OPCODE;
+ }
+
+ distance = to_addr - from_addr;
+
+ if (max_minimal_minus_distance <= distance
+ && distance <= max_minimal_plus_distance)
+ {
+ /* Create a "short" short jump: "BA distance - 2". */
+ storep[0] = branch_disp (distance - 2);
+ storep[1] = BA_QUICK_HIGH;
+
+ /* A nop for the delay slot. */
+ md_number_to_chars (storep + 2, nop_opcode, 2);
+
+ /* The extra word should be filled with something sane too. Make it
+ a nop to keep disassembly sane. */
+ md_number_to_chars (storep + 4, nop_opcode, 2);
+ }
+ else if (max_minus_distance <= distance
+ && distance <= max_plus_distance)
+ {
+ /* Make it a "long" short jump: "BA (PC+)". */
+ md_number_to_chars (storep, BA_PC_INCR_OPCODE, 2);
+
+ /* ".WORD distance - 4". */
+ md_number_to_chars (storep + 2,
+ (long) (distance - 4
+ - (cris_arch == arch_crisv32
+ ? -4 : 0)),
+ 2);
+
+ /* A nop for the delay slot. */
+ md_number_to_chars (storep + 4, nop_opcode, 2);
+ }
+ else
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _(".word case-table handling failed: table too large"));
+}
+
+/* Generate a long jump in a secondary jump table.
+
+ storep Where to store the jump instruction.
+ from_addr Address of the jump instruction.
+ to_addr Destination address of the jump.
+ fragP Which frag the destination address operand
+ lies in.
+ to_symbol Destination symbol. */
+
+void
+md_create_long_jump (char *storep, addressT from_addr, addressT to_addr,
+ fragS *fragP, symbolS *to_symbol)
+{
+ long int distance;
+
+ /* FIXME: What's that "+ 3"? It comes from the magic numbers that
+ used to be here, it's just translated to the limit macros used in
+ the relax table. But why + 3? */
+ long int max_short_minus_distance
+ = cris_arch != arch_crisv32 ? BRANCH_WB + 3 : BRANCH_WB_V32 + 3;
+
+ long int max_short_plus_distance
+ = cris_arch != arch_crisv32 ? BRANCH_WF + 3 : BRANCH_WF_V32 + 3;
+
+ distance = to_addr - from_addr;
+
+ if (max_short_minus_distance <= distance
+ && distance <= max_short_plus_distance)
+ /* Then make it a "short" long jump. */
+ md_create_short_jump (storep, from_addr, to_addr, fragP,
+ to_symbol);
+ else
+ {
+ /* We have a "long" long jump: "JUMP [PC+]". If CRISv32, always
+ make it a BA. Else make it an "MOVE [PC=PC+N],P0" if we're supposed
+ to emit PIC code. */
+ md_number_to_chars (storep,
+ cris_arch == arch_crisv32
+ ? BA_DWORD_OPCODE
+ : (pic ? MOVE_PC_INCR_OPCODE_PREFIX
+ : JUMP_PC_INCR_OPCODE),
+ 2);
+
+ /* Follow with a ".DWORD to_addr", PC-relative for PIC. */
+ fix_new (fragP, storep + 2 - fragP->fr_literal, 4, to_symbol,
+ cris_arch == arch_crisv32 ? 6 : 0,
+ cris_arch == arch_crisv32 || pic ? 1 : 0,
+ cris_arch == arch_crisv32 || pic
+ ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+
+ /* Follow it with a "NOP" for CRISv32. */
+ if (cris_arch == arch_crisv32)
+ md_number_to_chars (storep + 6, NOP_OPCODE_V32, 2);
+ else if (pic)
+ /* ...and the rest of the move-opcode for pre-v32 PIC. */
+ md_number_to_chars (storep + 6, MOVE_PC_INCR_OPCODE_SUFFIX, 2);
+ }
+}
+
+/* Allocate space for the first piece of an insn, and mark it as the
+ start of the insn for debug-format use. */
+
+static char *
+cris_insn_first_word_frag (void)
+{
+ char *insnp = frag_more (2);
+
+ /* We need to mark the start of the insn by passing dwarf2_emit_insn
+ the offset from the current fragment position. This must be done
+ after the first fragment is created but before any other fragments
+ (fixed or varying) are created. Note that the offset only
+ corresponds to the "size" of the insn for a fixed-size,
+ non-expanded insn. */
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ dwarf2_emit_insn (2);
+
+ return insnp;
+}
+
+/* Port-specific assembler initialization. */
+
+void
+md_begin (void)
+{
+ const char *hashret = NULL;
+ int i = 0;
+
+ /* Set up a hash table for the instructions. */
+ op_hash = hash_new ();
+ if (op_hash == NULL)
+ as_fatal (_("Virtual memory exhausted"));
+
+ /* Enable use of ".if ..asm.arch.cris.v32"
+ and ".if ..asm.arch.cris.common_v10_v32" and a few others. */
+ symbol_table_insert (symbol_new ("..asm.arch.cris.v32", absolute_section,
+ (cris_arch == arch_crisv32),
+ &zero_address_frag));
+ symbol_table_insert (symbol_new ("..asm.arch.cris.v10", absolute_section,
+ (cris_arch == arch_crisv10),
+ &zero_address_frag));
+ symbol_table_insert (symbol_new ("..asm.arch.cris.common_v10_v32",
+ absolute_section,
+ (cris_arch == arch_cris_common_v10_v32),
+ &zero_address_frag));
+ symbol_table_insert (symbol_new ("..asm.arch.cris.any_v0_v10",
+ absolute_section,
+ (cris_arch == arch_cris_any_v0_v10),
+ &zero_address_frag));
+
+ while (cris_opcodes[i].name != NULL)
+ {
+ const char *name = cris_opcodes[i].name;
+
+ if (! cris_insn_ver_valid_for_arch (cris_opcodes[i].applicable_version,
+ cris_arch))
+ {
+ i++;
+ continue;
+ }
+
+ /* Need to cast to get rid of "const". FIXME: Fix hash_insert instead. */
+ hashret = hash_insert (op_hash, name, (void *) &cris_opcodes[i]);
+
+ if (hashret != NULL && *hashret != '\0')
+ as_fatal (_("Can't hash `%s': %s\n"), cris_opcodes[i].name,
+ *hashret == 0 ? _("(unknown reason)") : hashret);
+ do
+ {
+ if (cris_opcodes[i].match & cris_opcodes[i].lose)
+ as_fatal (_("Buggy opcode: `%s' \"%s\"\n"), cris_opcodes[i].name,
+ cris_opcodes[i].args);
+
+ ++i;
+ }
+ while (cris_opcodes[i].name != NULL
+ && strcmp (cris_opcodes[i].name, name) == 0);
+ }
+}
+
+/* Assemble a source line. */
+
+void
+md_assemble (char *str)
+{
+ struct cris_instruction output_instruction;
+ struct cris_prefix prefix;
+ char *opcodep;
+ char *p;
+
+ know (str);
+
+ /* Do the low-level grunt - assemble to bits and split up into a prefix
+ and ordinary insn. */
+ cris_process_instruction (str, &output_instruction, &prefix);
+
+ /* Handle any prefixes to the instruction. */
+ switch (prefix.kind)
+ {
+ case PREFIX_NONE:
+ break;
+
+ /* When the expression is unknown for a BDAP, it can need 0, 2 or 4
+ extra bytes, so we handle it separately. */
+ case PREFIX_BDAP_IMM:
+ /* We only do it if the relocation is unspecified, i.e. not a PIC or TLS
+ relocation. */
+ if (prefix.reloc == BFD_RELOC_NONE)
+ {
+ gen_bdap (prefix.base_reg_number, &prefix.expr);
+ break;
+ }
+ /* Fall through. */
+ case PREFIX_BDAP:
+ case PREFIX_BIAP:
+ case PREFIX_DIP:
+ opcodep = cris_insn_first_word_frag ();
+
+ /* Output the prefix opcode. */
+ md_number_to_chars (opcodep, (long) prefix.opcode, 2);
+
+ /* Having a specified reloc only happens for DIP and for BDAP with
+ PIC or TLS operands, but it is ok to drop through here for the other
+ prefixes as they can have no relocs specified. */
+ if (prefix.reloc != BFD_RELOC_NONE)
+ {
+ unsigned int relocsize
+ = (prefix.kind == PREFIX_DIP
+ ? 4 : cris_get_specified_reloc_size (prefix.reloc));
+
+ p = frag_more (relocsize);
+ fix_new_exp (frag_now, (p - frag_now->fr_literal), relocsize,
+ &prefix.expr, 0, prefix.reloc);
+ }
+ break;
+
+ case PREFIX_PUSH:
+ opcodep = cris_insn_first_word_frag ();
+
+ /* Output the prefix opcode. Being a "push", we add the negative
+ size of the register to "sp". */
+ if (output_instruction.spec_reg != NULL)
+ {
+ /* Special register. */
+ opcodep[0] = -output_instruction.spec_reg->reg_size;
+ }
+ else
+ {
+ /* General register. */
+ opcodep[0] = -4;
+ }
+ opcodep[1] = (REG_SP << 4) + (BDAP_QUICK_OPCODE >> 8);
+ break;
+
+ default:
+ BAD_CASE (prefix.kind);
+ }
+
+ /* If we only had a prefix insn, we're done. */
+ if (output_instruction.insn_type == CRIS_INSN_NONE)
+ return;
+
+ /* Done with the prefix. Continue with the main instruction. */
+ if (prefix.kind == PREFIX_NONE)
+ opcodep = cris_insn_first_word_frag ();
+ else
+ opcodep = frag_more (2);
+
+ /* Output the instruction opcode. */
+ md_number_to_chars (opcodep, (long) (output_instruction.opcode), 2);
+
+ /* Output the symbol-dependent instruction stuff. */
+ if (output_instruction.insn_type == CRIS_INSN_BRANCH)
+ {
+ segT to_seg = absolute_section;
+ int is_undefined = 0;
+ int length_code;
+
+ if (output_instruction.expr.X_op != O_constant)
+ {
+ to_seg = S_GET_SEGMENT (output_instruction.expr.X_add_symbol);
+
+ if (to_seg == undefined_section)
+ is_undefined = 1;
+ }
+
+ if (to_seg == now_seg || is_undefined
+ /* In CRISv32, there *is* a 32-bit absolute branch, so don't
+ emit the 12-byte sequence for known symbols in other
+ segments. */
+ || (cris_arch == arch_crisv32
+ && output_instruction.opcode == BA_QUICK_OPCODE))
+ {
+ /* Handle complex expressions. */
+ valueT addvalue
+ = (SIMPLE_EXPR (&output_instruction.expr)
+ ? output_instruction.expr.X_add_number
+ : 0);
+ symbolS *sym
+ = (SIMPLE_EXPR (&output_instruction.expr)
+ ? output_instruction.expr.X_add_symbol
+ : make_expr_symbol (&output_instruction.expr));
+
+ /* If is_undefined, the expression may still become now_seg.
+ That case is handled by md_estimate_size_before_relax. */
+ length_code = to_seg == now_seg ? STATE_BYTE : STATE_UNDF;
+
+ /* Make room for max twelve bytes of variable length for v32 mode
+ or PIC, ten for v10 and older. */
+ frag_var (rs_machine_dependent,
+ (cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32
+ || pic) ? 12 : 10, 0,
+ ENCODE_RELAX (cris_arch == arch_crisv32
+ ? (output_instruction.opcode
+ == BA_QUICK_OPCODE
+ ? STATE_ABS_BRANCH_V32
+ : STATE_COND_BRANCH_V32)
+ : (cris_arch == arch_cris_common_v10_v32
+ ? STATE_COND_BRANCH_COMMON
+ : (pic ? STATE_COND_BRANCH_PIC
+ : STATE_COND_BRANCH)),
+ length_code),
+ sym, addvalue, opcodep);
+ }
+ else
+ {
+ /* We have: to_seg != now_seg && to_seg != undefined_section.
+ This means it is a branch to a known symbol in another
+ section, perhaps an absolute address. Emit a 32-bit branch. */
+ char *cond_jump
+ = frag_more ((cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32
+ || pic)
+ ? 12 : 10);
+
+ gen_cond_branch_32 (opcodep, cond_jump, frag_now,
+ output_instruction.expr.X_add_symbol,
+ (symbolS *) NULL,
+ output_instruction.expr.X_add_number);
+ }
+ }
+ else if (output_instruction.insn_type == CRIS_INSN_MUL
+ && err_for_dangerous_mul_placement)
+ /* Create a frag which which we track the location of the mul insn
+ (in the last two bytes before the mul-frag). */
+ frag_variant (rs_machine_dependent, 0, 0,
+ ENCODE_RELAX (STATE_MUL, STATE_BYTE),
+ NULL, 0, opcodep);
+ else
+ {
+ if (output_instruction.imm_oprnd_size > 0)
+ {
+ /* The instruction has an immediate operand. */
+ enum bfd_reloc_code_real reloc = BFD_RELOC_NONE;
+
+ switch (output_instruction.imm_oprnd_size)
+ {
+ /* Any byte-size immediate constants are treated as
+ word-size. FIXME: Thus overflow check does not work
+ correctly. */
+
+ case 2:
+ /* Note that size-check for the explicit reloc has already
+ been done when we get here. */
+ if (output_instruction.reloc != BFD_RELOC_NONE)
+ reloc = output_instruction.reloc;
+ else
+ reloc = BFD_RELOC_16;
+ break;
+
+ case 4:
+ /* Allow a relocation specified in the operand. */
+ if (output_instruction.reloc != BFD_RELOC_NONE)
+ reloc = output_instruction.reloc;
+ else
+ reloc = BFD_RELOC_32;
+ break;
+
+ default:
+ BAD_CASE (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.expr,
+ reloc == BFD_RELOC_32_PCREL
+ || reloc == BFD_RELOC_16_PCREL
+ || reloc == BFD_RELOC_8_PCREL, reloc);
+ }
+ else if (output_instruction.reloc == BFD_RELOC_CRIS_LAPCQ_OFFSET
+ && output_instruction.expr.X_md != 0)
+ {
+ /* Handle complex expressions. */
+ valueT addvalue
+ = (output_instruction.expr.X_op_symbol != NULL
+ ? 0 : output_instruction.expr.X_add_number);
+ symbolS *sym
+ = (output_instruction.expr.X_op_symbol != NULL
+ ? make_expr_symbol (&output_instruction.expr)
+ : output_instruction.expr.X_add_symbol);
+
+ /* This is a relaxing construct, so we need a frag_var rather
+ than the fix_new_exp call below. */
+ frag_var (rs_machine_dependent,
+ 4, 0,
+ ENCODE_RELAX (STATE_LAPC, STATE_UNDF),
+ sym, addvalue, opcodep);
+ }
+ else if (output_instruction.reloc != BFD_RELOC_NONE)
+ {
+ /* An immediate operand that has a relocation and needs to be
+ processed further. */
+
+ /* It is important to use fix_new_exp here and everywhere else
+ (and not fix_new), as fix_new_exp can handle "difference
+ expressions" - where the expression contains a difference of
+ two symbols in the same segment. */
+ fix_new_exp (frag_now, (opcodep - frag_now->fr_literal), 2,
+ &output_instruction.expr,
+ output_instruction.reloc == BFD_RELOC_32_PCREL
+ || output_instruction.reloc == BFD_RELOC_16_PCREL
+ || output_instruction.reloc == BFD_RELOC_8_PCREL
+ || (output_instruction.reloc
+ == BFD_RELOC_CRIS_LAPCQ_OFFSET),
+ output_instruction.reloc);
+ }
+ }
+}
+
+/* Low level text-to-bits assembly. */
+
+static void
+cris_process_instruction (char *insn_text, struct cris_instruction *out_insnp,
+ struct cris_prefix *prefixp)
+{
+ char *s;
+ char modified_char = 0;
+ const char *args;
+ struct cris_opcode *instruction;
+ char *operands;
+ int match = 0;
+ int mode;
+ int regno;
+ int size_bits;
+
+ /* Reset these fields to a harmless state in case we need to return in
+ error. */
+ prefixp->kind = PREFIX_NONE;
+ prefixp->reloc = BFD_RELOC_NONE;
+ out_insnp->insn_type = CRIS_INSN_NONE;
+ out_insnp->imm_oprnd_size = 0;
+
+ /* Find the end of the opcode mnemonic. We assume (true in 2.9.1)
+ that the caller has translated the opcode to lower-case, up to the
+ first non-letter. */
+ for (operands = insn_text; ISLOWER (*operands); ++operands)
+ ;
+
+ /* Terminate the opcode after letters, but save the character there if
+ it was of significance. */
+ switch (*operands)
+ {
+ case '\0':
+ break;
+
+ case '.':
+ /* Put back the modified character later. */
+ modified_char = *operands;
+ /* Fall through. */
+
+ case ' ':
+ /* Consume the character after the mnemonic
+ and replace it with '\0'. */
+ *operands++ = '\0';
+ break;
+
+ default:
+ as_bad (_("Unknown opcode: `%s'"), insn_text);
+ return;
+ }
+
+ /* Find the instruction. */
+ instruction = (struct cris_opcode *) hash_find (op_hash, insn_text);
+ if (instruction == NULL)
+ {
+ as_bad (_("Unknown opcode: `%s'"), insn_text);
+ return;
+ }
+
+ /* Put back the modified character. */
+ switch (modified_char)
+ {
+ case 0:
+ break;
+
+ default:
+ *--operands = modified_char;
+ }
+
+ /* Try to match an opcode table slot. */
+ for (s = operands;;)
+ {
+ int imm_expr_found;
+
+ /* Initialize *prefixp, perhaps after being modified for a
+ "near match". */
+ prefixp->kind = PREFIX_NONE;
+ prefixp->reloc = BFD_RELOC_NONE;
+
+ /* Initialize *out_insnp. */
+ memset (out_insnp, 0, sizeof (*out_insnp));
+ out_insnp->opcode = instruction->match;
+ out_insnp->reloc = BFD_RELOC_NONE;
+ out_insnp->insn_type = CRIS_INSN_NORMAL;
+ out_insnp->imm_oprnd_size = 0;
+
+ imm_expr_found = 0;
+
+ /* Build the opcode, checking as we go to make sure that the
+ operands match. */
+ for (args = instruction->args;; ++args)
+ {
+ switch (*args)
+ {
+ case '\0':
+ /* If we've come to the end of arguments, we're done. */
+ if (*s == '\0')
+ match = 1;
+ break;
+
+ case '!':
+ /* Non-matcher character for disassembly.
+ Ignore it here. */
+ continue;
+
+ case '[':
+ case ']':
+ case ',':
+ case ' ':
+ /* These must match exactly. */
+ if (*s++ == *args)
+ continue;
+ break;
+
+ case 'A':
+ /* "ACR", case-insensitive.
+ Handle a sometimes-mandatory dollar sign as register
+ prefix. */
+ if (*s == REGISTER_PREFIX_CHAR)
+ s++;
+ else if (demand_register_prefix)
+ break;
+
+ if ((*s++ != 'a' && s[-1] != 'A')
+ || (*s++ != 'c' && s[-1] != 'C')
+ || (*s++ != 'r' && s[-1] != 'R'))
+ break;
+ continue;
+
+ case 'B':
+ /* This is not really an operand, but causes a "BDAP
+ -size,SP" prefix to be output, for PUSH instructions. */
+ prefixp->kind = PREFIX_PUSH;
+ continue;
+
+ case 'b':
+ /* This letter marks an operand that should not be matched
+ in the assembler. It is a branch with 16-bit
+ displacement. The assembler will create them from the
+ 8-bit flavor when necessary. The assembler does not
+ support the [rN+] operand, as the [r15+] that is
+ generated for 16-bit displacements. */
+ break;
+
+ case 'c':
+ /* A 5-bit unsigned immediate in bits <4:0>. */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+ else
+ {
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 31))
+ as_bad (_("Immediate value not in 5 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+
+ out_insnp->reloc = BFD_RELOC_CRIS_UNSIGNED_5;
+ continue;
+ }
+
+ case 'C':
+ /* A 4-bit unsigned immediate in bits <3:0>. */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+ else
+ {
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 15))
+ as_bad (_("Immediate value not in 4 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+
+ out_insnp->reloc = BFD_RELOC_CRIS_UNSIGNED_4;
+ continue;
+ }
+
+ /* For 'd', check for an optional ".d" or ".D" at the
+ start of the operands, followed by a space character. */
+ case 'd':
+ if (modified_char == '.' && *s == '.')
+ {
+ if ((s[1] != 'd' && s[1] == 'D')
+ || ! ISSPACE (s[2]))
+ break;
+ s += 2;
+ continue;
+ }
+ continue;
+
+ case 'D':
+ /* General register in bits <15:12> and <3:0>. */
+ if (! get_gen_reg (&s, &regno))
+ break;
+ else
+ {
+ out_insnp->opcode |= regno /* << 0 */;
+ out_insnp->opcode |= regno << 12;
+ continue;
+ }
+
+ case 'f':
+ /* Flags from the condition code register. */
+ {
+ int flags = 0;
+
+ if (! get_flags (&s, &flags))
+ break;
+
+ out_insnp->opcode |= ((flags & 0xf0) << 8) | (flags & 0xf);
+ continue;
+ }
+
+ case 'i':
+ /* A 6-bit signed immediate in bits <5:0>. */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+ else
+ {
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < -32
+ || out_insnp->expr.X_add_number > 31))
+ as_bad (_("Immediate value not in 6 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ out_insnp->reloc = BFD_RELOC_CRIS_SIGNED_6;
+ continue;
+ }
+
+ case 'I':
+ /* A 6-bit unsigned immediate in bits <5:0>. */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+ else
+ {
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 63))
+ as_bad (_("Immediate value not in 6 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+ out_insnp->reloc = BFD_RELOC_CRIS_UNSIGNED_6;
+ continue;
+ }
+
+ case 'M':
+ /* A size modifier, B, W or D, to be put in a bit position
+ suitable for CLEAR instructions (i.e. reflecting a zero
+ register). */
+ if (! get_bwd_size_modifier (&s, &size_bits))
+ break;
+ else
+ {
+ switch (size_bits)
+ {
+ case 0:
+ out_insnp->opcode |= 0 << 12;
+ break;
+
+ case 1:
+ out_insnp->opcode |= 4 << 12;
+ break;
+
+ case 2:
+ out_insnp->opcode |= 8 << 12;
+ break;
+ }
+ continue;
+ }
+
+ case 'm':
+ /* A size modifier, B, W or D, to be put in bits <5:4>. */
+ if (modified_char != '.'
+ || ! get_bwd_size_modifier (&s, &size_bits))
+ break;
+ else
+ {
+ out_insnp->opcode |= size_bits << 4;
+ continue;
+ }
+
+ case 'o':
+ /* A branch expression. */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+ else
+ {
+ out_insnp->insn_type = CRIS_INSN_BRANCH;
+ continue;
+ }
+
+ case 'Q':
+ /* A 8-bit quick BDAP expression, "expr,R". */
+ if (! cris_get_expression (&s, &out_insnp->expr))
+ break;
+
+ if (*s != ',')
+ break;
+
+ s++;
+
+ if (!get_gen_reg (&s, &regno))
+ break;
+
+ out_insnp->opcode |= regno << 12;
+ out_insnp->reloc = BFD_RELOC_CRIS_SIGNED_8;
+ continue;
+
+ case 'O':
+ /* A BDAP expression for any size, "expr,R". */
+ if (! cris_get_expression (&s, &prefixp->expr))
+ break;
+ else
+ {
+ if (*s != ',')
+ break;
+
+ s++;
+
+ if (!get_gen_reg (&s, &prefixp->base_reg_number))
+ break;
+
+ /* Since 'O' is used with an explicit bdap, we have no
+ "real" instruction. */
+ prefixp->kind = PREFIX_BDAP_IMM;
+ prefixp->opcode
+ = BDAP_QUICK_OPCODE | (prefixp->base_reg_number << 12);
+
+ out_insnp->insn_type = CRIS_INSN_NONE;
+ continue;
+ }
+
+ case 'P':
+ /* Special register in bits <15:12>. */
+ if (! get_spec_reg (&s, &out_insnp->spec_reg))
+ break;
+ else
+ {
+ /* Use of some special register names come with a
+ specific warning. Note that we have no ".cpu type"
+ pseudo yet, so some of this is just unused
+ framework. */
+ if (out_insnp->spec_reg->warning)
+ as_warn ("%s", out_insnp->spec_reg->warning);
+ else if (out_insnp->spec_reg->applicable_version
+ == cris_ver_warning)
+ /* Others have a generic warning. */
+ as_warn (_("Unimplemented register `%s' specified"),
+ out_insnp->spec_reg->name);
+
+ out_insnp->opcode
+ |= out_insnp->spec_reg->number << 12;
+ continue;
+ }
+
+ case 'p':
+ /* This character is used in the disassembler to
+ recognize a prefix instruction to fold into the
+ addressing mode for the next instruction. It is
+ ignored here. */
+ continue;
+
+ case 'R':
+ /* General register in bits <15:12>. */
+ if (! get_gen_reg (&s, &regno))
+ break;
+ else
+ {
+ out_insnp->opcode |= regno << 12;
+ continue;
+ }
+
+ case 'r':
+ /* General register in bits <3:0>. */
+ if (! get_gen_reg (&s, &regno))
+ break;
+ else
+ {
+ out_insnp->opcode |= regno /* << 0 */;
+ continue;
+ }
+
+ case 'S':
+ /* Source operand in bit <10> and a prefix; a 3-operand
+ prefix. */
+ if (! get_3op_or_dip_prefix_op (&s, prefixp))
+ break;
+ else
+ continue;
+
+ case 's':
+ /* Source operand in bits <10>, <3:0> and optionally a
+ prefix; i.e. an indirect operand or an side-effect
+ prefix (where valid). */
+ if (! get_autoinc_prefix_or_indir_op (&s, prefixp, &mode,
+ &regno,
+ &imm_expr_found,
+ &out_insnp->expr))
+ break;
+ else
+ {
+ if (prefixp->kind != PREFIX_NONE)
+ {
+ /* A prefix, so it has the autoincrement bit
+ set. */
+ out_insnp->opcode |= (AUTOINCR_BIT << 8);
+ }
+ else
+ {
+ /* No prefix. The "mode" variable contains bits like
+ whether or not this is autoincrement mode. */
+ out_insnp->opcode |= (mode << 10);
+
+ /* If there was a reloc specifier, then it was
+ attached to the prefix. Note that we can't check
+ that the reloc size matches, since we don't have
+ all the operands yet in all cases. */
+ if (prefixp->reloc != BFD_RELOC_NONE)
+ out_insnp->reloc = prefixp->reloc;
+ }
+
+ out_insnp->opcode |= regno /* << 0 */ ;
+ continue;
+ }
+
+ case 'N':
+ case 'Y':
+ /* Like 's', but immediate operand only. Also do not
+ modify insn. There are no insns where an explicit reloc
+ specifier makes sense. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ imm_expr_found = 1;
+ continue;
+ }
+ break;
+
+ case 'n':
+ /* Like 'N', but PC-relative to the start of the insn.
+ There might be a :PLT to request a PLT entry. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ imm_expr_found = 1;
+ out_insnp->reloc = BFD_RELOC_32_PCREL;
+
+ /* We have to adjust the expression, because that
+ relocation is to the location *after* the
+ relocation. So add 2 for the insn and 4 for the
+ relocation. */
+ out_insnp->expr.X_add_number += 6;
+
+ /* TLS specifiers do not make sense here. */
+ if (pic && *s == RELOC_SUFFIX_CHAR)
+ cris_get_reloc_suffix (&s, &out_insnp->reloc,
+ &out_insnp->expr);
+
+ continue;
+ }
+ break;
+
+ case 'U':
+ /* Maybe 'u', maybe 'n'. Only for LAPC/LAPCQ. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ out_insnp->reloc = BFD_RELOC_CRIS_LAPCQ_OFFSET;
+
+ /* Define 1 as relaxing. */
+ out_insnp->expr.X_md = 1;
+ continue;
+ }
+ break;
+
+ case 'u':
+ /* Four PC-relative bits in <3:0> representing <4:1>:0 of
+ an offset relative to the beginning of the current
+ insn. */
+ if (cris_get_expression (&s, &out_insnp->expr))
+ {
+ out_insnp->reloc = BFD_RELOC_CRIS_LAPCQ_OFFSET;
+
+ /* Define 0 as non-relaxing. */
+ out_insnp->expr.X_md = 0;
+
+ /* We have to adjust the expression, because that
+ relocation is to the location *after* the
+ insn. So add 2 for the insn. */
+ out_insnp->expr.X_add_number += 2;
+ continue;
+ }
+ break;
+
+ case 'x':
+ /* Rs.m in bits <15:12> and <5:4>. */
+ if (! get_gen_reg (&s, &regno)
+ || ! get_bwd_size_modifier (&s, &size_bits))
+ break;
+ else
+ {
+ out_insnp->opcode |= (regno << 12) | (size_bits << 4);
+ continue;
+ }
+
+ case 'y':
+ /* Source operand in bits <10>, <3:0> and optionally a
+ prefix; i.e. an indirect operand or an side-effect
+ prefix.
+
+ The difference to 's' is that this does not allow an
+ "immediate" expression. */
+ if (! get_autoinc_prefix_or_indir_op (&s, prefixp,
+ &mode, &regno,
+ &imm_expr_found,
+ &out_insnp->expr)
+ || imm_expr_found)
+ break;
+ else
+ {
+ if (prefixp->kind != PREFIX_NONE)
+ {
+ /* A prefix, and those matched here always have
+ side-effects (see 's' case). */
+ out_insnp->opcode |= (AUTOINCR_BIT << 8);
+ }
+ else
+ {
+ /* No prefix. The "mode" variable contains bits
+ like whether or not this is autoincrement
+ mode. */
+ out_insnp->opcode |= (mode << 10);
+ }
+
+ out_insnp->opcode |= regno /* << 0 */;
+ continue;
+ }
+
+ case 'z':
+ /* Size modifier (B or W) in bit <4>. */
+ if (! get_bw_size_modifier (&s, &size_bits))
+ break;
+ else
+ {
+ out_insnp->opcode |= size_bits << 4;
+ continue;
+ }
+
+ case 'T':
+ if (cris_arch == arch_crisv32
+ && get_sup_reg (&s, &regno))
+ {
+ out_insnp->opcode |= regno << 12;
+ continue;
+ }
+ break;
+
+ default:
+ BAD_CASE (*args);
+ }
+
+ /* We get here when we fail a match above or we found a
+ complete match. Break out of this loop. */
+ break;
+ }
+
+ /* Was it a match or a miss? */
+ if (match == 0)
+ {
+ /* If it's just that the args don't match, maybe the next
+ item in the table is the same opcode but with
+ matching operands. First skip any invalid ones. */
+ while (instruction[1].name != NULL
+ && strcmp (instruction->name, instruction[1].name) == 0
+ && ! cris_insn_ver_valid_for_arch (instruction[1]
+ .applicable_version,
+ cris_arch))
+ ++instruction;
+
+ if (instruction[1].name != NULL
+ && strcmp (instruction->name, instruction[1].name) == 0
+ && cris_insn_ver_valid_for_arch (instruction[1]
+ .applicable_version,
+ cris_arch))
+ {
+ /* Yep. Restart and try that one instead. */
+ ++instruction;
+ s = operands;
+ continue;
+ }
+ else
+ {
+ /* We've come to the end of instructions with this
+ opcode, so it must be an error. */
+ as_bad (_("Illegal operands"));
+
+ /* As discard_rest_of_line, but without continuing to the
+ next line. */
+ while (!is_end_of_line[(unsigned char) *input_line_pointer])
+ input_line_pointer++;
+ return;
+ }
+ }
+ else
+ {
+ /* We have a match. Check if there's anything more to do. */
+ if (imm_expr_found)
+ {
+ /* There was an immediate mode operand, so we must check
+ that it has an appropriate size. */
+ switch (instruction->imm_oprnd_size)
+ {
+ default:
+ case SIZE_NONE:
+ /* Shouldn't happen; this one does not have immediate
+ operands with different sizes. */
+ BAD_CASE (instruction->imm_oprnd_size);
+ break;
+
+ case SIZE_FIX_32:
+ out_insnp->imm_oprnd_size = 4;
+ break;
+
+ case SIZE_SPEC_REG:
+ if (cris_arch == arch_crisv32)
+ /* All immediate loads of special registers are
+ 32-bit on CRISv32. */
+ out_insnp->imm_oprnd_size = 4;
+ else
+ switch (out_insnp->spec_reg->reg_size)
+ {
+ case 1:
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < -128
+ || out_insnp->expr.X_add_number > 255))
+ as_bad (_("Immediate value not in 8 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ /* Fall through. */
+ case 2:
+ /* FIXME: We need an indicator in the instruction
+ table to pass on, to indicate if we need to check
+ overflow for a signed or unsigned number. */
+ if (out_insnp->expr.X_op == O_constant
+ && (out_insnp->expr.X_add_number < -32768
+ || out_insnp->expr.X_add_number > 65535))
+ as_bad (_("Immediate value not in 16 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ out_insnp->imm_oprnd_size = 2;
+ break;
+
+ case 4:
+ out_insnp->imm_oprnd_size = 4;
+ break;
+
+ default:
+ BAD_CASE (out_insnp->spec_reg->reg_size);
+ }
+ break;
+
+ case SIZE_FIELD:
+ case SIZE_FIELD_SIGNED:
+ case SIZE_FIELD_UNSIGNED:
+ switch (size_bits)
+ {
+ /* FIXME: Find way to pass un/signedness to
+ caller, and set reloc type instead, postponing
+ this check until cris_number_to_imm. That
+ necessarily corrects the reloc type for the
+ byte case, maybe requiring further changes. */
+ case 0:
+ if (out_insnp->expr.X_op == O_constant)
+ {
+ if (instruction->imm_oprnd_size == SIZE_FIELD
+ && (out_insnp->expr.X_add_number < -128
+ || out_insnp->expr.X_add_number > 255))
+ as_bad (_("Immediate value not in 8 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_SIGNED
+ && (out_insnp->expr.X_add_number < -128
+ || out_insnp->expr.X_add_number > 127))
+ as_bad (_("Immediate value not in 8 bit signed range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_UNSIGNED
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 255))
+ as_bad (_("Immediate value not in 8 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+ }
+
+ /* Fall through. */
+ case 1:
+ if (out_insnp->expr.X_op == O_constant)
+ {
+ if (instruction->imm_oprnd_size == SIZE_FIELD
+ && (out_insnp->expr.X_add_number < -32768
+ || out_insnp->expr.X_add_number > 65535))
+ as_bad (_("Immediate value not in 16 bit range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_SIGNED
+ && (out_insnp->expr.X_add_number < -32768
+ || out_insnp->expr.X_add_number > 32767))
+ as_bad (_("Immediate value not in 16 bit signed range: %ld"),
+ out_insnp->expr.X_add_number);
+ else if (instruction->imm_oprnd_size == SIZE_FIELD_UNSIGNED
+ && (out_insnp->expr.X_add_number < 0
+ || out_insnp->expr.X_add_number > 65535))
+ as_bad (_("Immediate value not in 16 bit unsigned range: %ld"),
+ out_insnp->expr.X_add_number);
+ }
+ out_insnp->imm_oprnd_size = 2;
+ break;
+
+ case 2:
+ out_insnp->imm_oprnd_size = 4;
+ break;
+
+ default:
+ BAD_CASE (out_insnp->spec_reg->reg_size);
+ }
+ }
+
+ /* If there was a relocation specified for the immediate
+ expression (i.e. it had a PIC or TLS modifier) check that the
+ size of the relocation matches the size specified by
+ the opcode. */
+ if (out_insnp->reloc != BFD_RELOC_NONE
+ && (cris_get_specified_reloc_size (out_insnp->reloc)
+ != (unsigned int) out_insnp->imm_oprnd_size))
+ as_bad (out_insnp->reloc == BFD_RELOC_CRIS_32_GD
+ || out_insnp->reloc == BFD_RELOC_CRIS_32_TPREL
+ || out_insnp->reloc == BFD_RELOC_CRIS_16_TPREL
+ || out_insnp->reloc == BFD_RELOC_CRIS_32_IE
+ ? _("TLS relocation size does not match operand size")
+ : _("PIC relocation size does not match operand size"));
+ }
+ else if (instruction->op == cris_muls_op
+ || instruction->op == cris_mulu_op)
+ out_insnp->insn_type = CRIS_INSN_MUL;
+ }
+ break;
+ }
+}
+
+/* Get a B, W, or D size modifier from the string pointed out by *cPP,
+ which must point to a '.' in front of the modifier. On successful
+ return, *cPP is advanced to the character following the size
+ modifier, and is undefined otherwise.
+
+ cPP Pointer to pointer to string starting
+ with the size modifier.
+
+ size_bitsp Pointer to variable to contain the size bits on
+ successful return.
+
+ Return 1 iff a correct size modifier is found, else 0. */
+
+static int
+get_bwd_size_modifier (char **cPP, int *size_bitsp)
+{
+ if (**cPP != '.')
+ return 0;
+ else
+ {
+ /* Consume the '.'. */
+ (*cPP)++;
+
+ switch (**cPP)
+ {
+ case 'B':
+ case 'b':
+ *size_bitsp = 0;
+ break;
+
+ case 'W':
+ case 'w':
+ *size_bitsp = 1;
+ break;
+
+ case 'D':
+ case 'd':
+ *size_bitsp = 2;
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* Consume the size letter. */
+ (*cPP)++;
+ return 1;
+ }
+}
+
+/* Get a B or W size modifier from the string pointed out by *cPP,
+ which must point to a '.' in front of the modifier. On successful
+ return, *cPP is advanced to the character following the size
+ modifier, and is undefined otherwise.
+
+ cPP Pointer to pointer to string starting
+ with the size modifier.
+
+ size_bitsp Pointer to variable to contain the size bits on
+ successful return.
+
+ Return 1 iff a correct size modifier is found, else 0. */
+
+static int
+get_bw_size_modifier (char **cPP, int *size_bitsp)
+{
+ if (**cPP != '.')
+ return 0;
+ else
+ {
+ /* Consume the '.'. */
+ (*cPP)++;
+
+ switch (**cPP)
+ {
+ case 'B':
+ case 'b':
+ *size_bitsp = 0;
+ break;
+
+ case 'W':
+ case 'w':
+ *size_bitsp = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* Consume the size letter. */
+ (*cPP)++;
+ return 1;
+ }
+}
+
+/* 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.
+
+ cPP Pointer to pointer to string, beginning with a general
+ register name.
+
+ regnop Pointer to int containing the register number.
+
+ Return 1 iff a correct general register designator is found,
+ else 0. */
+
+static int
+get_gen_reg (char **cPP, int *regnop)
+{
+ 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':
+ case 'p':
+ /* "P" as in "PC"? Consume the "P". */
+ (*cPP)++;
+
+ if ((**cPP == 'C' || **cPP == 'c')
+ && ! ISALNUM ((*cPP)[1])
+ /* Here's a little twist: For v32 and the compatibility mode,
+ we only recognize PC as a register number if there's '+]'
+ after. We don't consume that, but the presence can only be
+ valid after a register in a post-increment context, which
+ is also the only valid context for PC as a register for
+ v32. Not that it's used very often, but saying "MOVE.D
+ [PC+],R5" should remain valid. It's not supported for
+ jump-type insns or other insns with no [Rn+] mode, though. */
+ && ((cris_arch != arch_crisv32
+ && cris_arch != arch_cris_common_v10_v32)
+ || ((*cPP)[1] == '+' && (*cPP)[2] == ']')))
+ {
+ /* It's "PC": consume the "c" and we're done. */
+ (*cPP)++;
+ *regnop = REG_PC;
+ return 1;
+ }
+ break;
+
+ /* Like with PC, we recognize ACR, but only if it's *not* followed
+ by '+', and only for v32. */
+ case 'A':
+ case 'a':
+ if (cris_arch != arch_crisv32
+ || ((*cPP)[1] != 'c' && (*cPP)[1] != 'C')
+ || ((*cPP)[2] != 'r' && (*cPP)[2] != 'R')
+ || ISALNUM ((*cPP)[3])
+ || (*cPP)[3] == '+')
+ break;
+ (*cPP) += 3;
+ *regnop = 15;
+ return 1;
+
+ case 'R':
+ case 'r':
+ /* Hopefully r[0-9] or r1[0-5]. Consume 'R' or 'r'. */
+ (*cPP)++;
+
+ if (ISDIGIT (**cPP))
+ {
+ /* It's r[0-9]. Consume and check the next digit. */
+ *regnop = **cPP - '0';
+ (*cPP)++;
+
+ if (! ISALNUM (**cPP))
+ {
+ /* No more digits, we're done. */
+ return 1;
+ }
+ else
+ {
+ /* One more digit. Consume and add. */
+ *regnop = *regnop * 10 + (**cPP - '0');
+
+ /* We need to check for a valid register number; Rn,
+ 0 <= n <= MAX_REG. */
+ if (*regnop <= MAX_REG)
+ {
+ /* Consume second digit. */
+ (*cPP)++;
+ return 1;
+ }
+ }
+ }
+ break;
+
+ case 'S':
+ case 's':
+ /* "S" as in "SP"? Consume the "S". */
+ (*cPP)++;
+ if (**cPP == 'P' || **cPP == 'p')
+ {
+ /* It's "SP": consume the "p" and we're done. */
+ (*cPP)++;
+ *regnop = REG_SP;
+ return 1;
+ }
+ break;
+
+ default:
+ /* Just here to silence compilation warnings. */
+ ;
+ }
+
+ /* We get here if we fail. Restore the pointer. */
+ *cPP = oldp;
+ return 0;
+}
+
+/* Get a special register from the string pointed out by *cPP. The
+ variable *cPP is advanced to the character following the special
+ register name if one is found, and retains its original position
+ otherwise.
+
+ cPP Pointer to pointer to string starting with a special register
+ name.
+
+ sregpp Pointer to Pointer to struct spec_reg, where a pointer to the
+ register description will be stored.
+
+ Return 1 iff a correct special register name is found. */
+
+static int
+get_spec_reg (char **cPP, const struct cris_spec_reg **sregpp)
+{
+ 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 = name_begin;
+ s2 = sregp->name;
+
+ while (*s2 != '\0' && TOLOWER (*s1) == *s2)
+ {
+ s1++;
+ s2++;
+ }
+
+ /* For a match, we must have consumed the name in the table, and we
+ must be outside what could be part of a name. Assume here that a
+ test for alphanumerics is sufficient for a name test. */
+ if (*s2 == 0 && ! ISALNUM (*s1)
+ && cris_insn_ver_valid_for_arch (sregp->applicable_version,
+ cris_arch))
+ {
+ /* We have a match. Update the pointer and be done. */
+ *cPP = s1;
+ *sregpp = sregp;
+ return 1;
+ }
+ }
+
+ /* If we got here, we did not find any name. */
+ return 0;
+}
+
+/* Get a support register from the string pointed out by *cPP. The
+ variable *cPP is advanced to the character following the support-
+ register name if one is found, and retains its original position
+ otherwise.
+
+ cPP Pointer to pointer to string starting with a support-register
+ name.
+
+ sregpp Pointer to int containing the register number.
+
+ Return 1 iff a correct support-register name is found. */
+
+static int
+get_sup_reg (char **cPP, int *regnop)
+{
+ char *s1;
+ const char *s2;
+ char *name_begin = *cPP;
+
+ const struct cris_support_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 support-registers. */
+ for (sregp = cris_support_regs; sregp->name != NULL; sregp++)
+ {
+ /* Start over from beginning of the supposed name. */
+ s1 = name_begin;
+ s2 = sregp->name;
+
+ while (*s2 != '\0' && TOLOWER (*s1) == *s2)
+ {
+ s1++;
+ s2++;
+ }
+
+ /* For a match, we must have consumed the name in the table, and we
+ must be outside what could be part of a name. Assume here that a
+ test for alphanumerics is sufficient for a name test. */
+ if (*s2 == 0 && ! ISALNUM (*s1))
+ {
+ /* We have a match. Update the pointer and be done. */
+ *cPP = s1;
+ *regnop = sregp->number;
+ return 1;
+ }
+ }
+
+ /* If we got here, we did not find any name. */
+ return 0;
+}
+
+/* Get an unprefixed or side-effect-prefix operand from the string pointed
+ out by *cPP. The pointer *cPP is advanced to the character following
+ the indirect operand if we have success, else it contains an undefined
+ value.
+
+ cPP Pointer to pointer to string beginning with the first
+ character of the supposed operand.
+
+ prefixp Pointer to structure containing an optional instruction
+ prefix.
+
+ is_autoincp Pointer to int indicating the indirect or autoincrement
+ bits.
+
+ src_regnop Pointer to int containing the source register number in
+ the instruction.
+
+ imm_foundp Pointer to an int indicating if an immediate expression
+ is found.
+
+ imm_exprP Pointer to a structure containing an immediate
+ expression, if success and if *imm_foundp is nonzero.
+
+ Return 1 iff a correct indirect operand is found. */
+
+static int
+get_autoinc_prefix_or_indir_op (char **cPP, struct cris_prefix *prefixp,
+ int *is_autoincp, int *src_regnop,
+ int *imm_foundp, expressionS *imm_exprP)
+{
+ /* Assume there was no immediate mode expression. */
+ *imm_foundp = 0;
+
+ if (**cPP == '[')
+ {
+ /* So this operand is one of:
+ Indirect: [rN]
+ Autoincrement: [rN+]
+ Indexed with assign: [rN=rM+rO.S]
+ Offset with assign: [rN=rM+I], [rN=rM+[rO].s], [rN=rM+[rO+].s]
+
+ Either way, consume the '['. */
+ (*cPP)++;
+
+ /* Get the rN register. */
+ if (! get_gen_reg (cPP, src_regnop))
+ /* If there was no register, then this cannot match. */
+ return 0;
+ else
+ {
+ /* We got the register, now check the next character. */
+ switch (**cPP)
+ {
+ case ']':
+ /* Indirect mode. We're done here. */
+ prefixp->kind = PREFIX_NONE;
+ *is_autoincp = 0;
+ break;
+
+ case '+':
+ /* This must be an auto-increment mode, if there's a
+ match. */
+ prefixp->kind = PREFIX_NONE;
+ *is_autoincp = 1;
+
+ /* We consume this character and break out to check the
+ closing ']'. */
+ (*cPP)++;
+ break;
+
+ case '=':
+ /* This must be indexed with assign, or offset with assign
+ to match. Not supported for crisv32 or in
+ compatibility mode. */
+ if (cris_arch == arch_crisv32
+ || cris_arch == arch_cris_common_v10_v32)
+ return 0;
+
+ (*cPP)++;
+
+ /* Either way, the next thing must be a register. */
+ if (! get_gen_reg (cPP, &prefixp->base_reg_number))
+ /* No register, no match. */
+ return 0;
+ else
+ {
+ /* We've consumed "[rN=rM", so we must be looking at
+ "+rO.s]" or "+I]", or "-I]", or "+[rO].s]" or
+ "+[rO+].s]". */
+ if (**cPP == '+')
+ {
+ int index_reg_number;
+ (*cPP)++;
+
+ if (**cPP == '[')
+ {
+ int size_bits;
+ /* This must be [rx=ry+[rz].s] or
+ [rx=ry+[rz+].s] or no match. We must be
+ looking at rz after consuming the '['. */
+ (*cPP)++;
+
+ if (!get_gen_reg (cPP, &index_reg_number))
+ return 0;
+
+ prefixp->kind = PREFIX_BDAP;
+ prefixp->opcode
+ = (BDAP_INDIR_OPCODE
+ + (prefixp->base_reg_number << 12)
+ + index_reg_number);
+
+ if (**cPP == '+')
+ {
+ /* We've seen "[rx=ry+[rz+" here, so now we
+ know that there must be "].s]" left to
+ check. */
+ (*cPP)++;
+ prefixp->opcode |= AUTOINCR_BIT << 8;
+ }
+
+ /* If it wasn't autoincrement, we don't need to
+ add anything. */
+
+ /* Check the next-to-last ']'. */
+ if (**cPP != ']')
+ return 0;
+
+ (*cPP)++;
+
+ /* Check the ".s" modifier. */
+ if (! get_bwd_size_modifier (cPP, &size_bits))
+ return 0;
+
+ prefixp->opcode |= size_bits << 4;
+
+ /* Now we got [rx=ry+[rz+].s or [rx=ry+[rz].s.
+ We break out to check the final ']'. */
+ break;
+ }
+ /* It wasn't an indirection. Check if it's a
+ register. */
+ else if (get_gen_reg (cPP, &index_reg_number))
+ {
+ int size_bits;
+
+ /* Indexed with assign mode: "[rN+rM.S]". */
+ prefixp->kind = PREFIX_BIAP;
+ prefixp->opcode
+ = (BIAP_OPCODE + (index_reg_number << 12)
+ + prefixp->base_reg_number /* << 0 */);
+
+ if (! get_bwd_size_modifier (cPP, &size_bits))
+ /* Size missing, this isn't a match. */
+ return 0;
+ else
+ {
+ /* Size found, break out to check the
+ final ']'. */
+ prefixp->opcode |= size_bits << 4;
+ break;
+ }
+ }
+ /* Not a register. Then this must be "[rN+I]". */
+ else if (cris_get_expression (cPP, &prefixp->expr))
+ {
+ /* We've got offset with assign mode. Fill
+ in the blanks and break out to match the
+ final ']'. */
+ prefixp->kind = PREFIX_BDAP_IMM;
+
+ /* We tentatively put an opcode corresponding to
+ a 32-bit operand here, although it may be
+ relaxed when there's no relocation
+ specifier for the operand. */
+ prefixp->opcode
+ = (BDAP_INDIR_OPCODE
+ | (prefixp->base_reg_number << 12)
+ | (AUTOINCR_BIT << 8)
+ | (2 << 4)
+ | REG_PC /* << 0 */);
+
+ /* This can have a PIC suffix, specifying reloc
+ type to use. */
+ if ((pic || tls) && **cPP == RELOC_SUFFIX_CHAR)
+ {
+ unsigned int relocsize;
+
+ cris_get_reloc_suffix (cPP, &prefixp->reloc,
+ &prefixp->expr);
+
+ /* Tweak the size of the immediate operand
+ in the prefix opcode if it isn't what we
+ set. */
+ relocsize
+ = cris_get_specified_reloc_size (prefixp->reloc);
+ if (relocsize != 4)
+ prefixp->opcode
+ = ((prefixp->opcode & ~(3 << 4))
+ | ((relocsize >> 1) << 4));
+ }
+ break;
+ }
+ else
+ /* Neither register nor expression found, so
+ this can't be a match. */
+ return 0;
+ }
+ /* Not "[rN+" but perhaps "[rN-"? */
+ else if (**cPP == '-')
+ {
+ /* We must have an offset with assign mode. */
+ if (! cris_get_expression (cPP, &prefixp->expr))
+ /* No expression, no match. */
+ return 0;
+ else
+ {
+ /* We've got offset with assign mode. Fill
+ in the blanks and break out to match the
+ final ']'.
+
+ Note that we don't allow a relocation
+ suffix for an operand with a minus
+ sign. */
+ prefixp->kind = PREFIX_BDAP_IMM;
+ break;
+ }
+ }
+ else
+ /* Neither '+' nor '-' after "[rN=rM". Lose. */
+ return 0;
+ }
+ default:
+ /* Neither ']' nor '+' nor '=' after "[rN". Lose. */
+ return 0;
+ }
+ }
+
+ /* When we get here, we have a match and will just check the closing
+ ']'. We can still fail though. */
+ if (**cPP != ']')
+ return 0;
+ else
+ {
+ /* Don't forget to consume the final ']'.
+ Then return in glory. */
+ (*cPP)++;
+ return 1;
+ }
+ }
+ /* No indirection. Perhaps a constant? */
+ else if (cris_get_expression (cPP, imm_exprP))
+ {
+ /* Expression found, this is immediate mode. */
+ prefixp->kind = PREFIX_NONE;
+ *is_autoincp = 1;
+ *src_regnop = REG_PC;
+ *imm_foundp = 1;
+
+ /* This can have a PIC suffix, specifying reloc type to use. The
+ caller must check that the reloc size matches the operand size. */
+ if ((pic || tls) && **cPP == RELOC_SUFFIX_CHAR)
+ cris_get_reloc_suffix (cPP, &prefixp->reloc, imm_exprP);
+
+ return 1;
+ }
+
+ /* No luck today. */
+ return 0;
+}
+
+/* This function gets an indirect operand in a three-address operand
+ combination from the string pointed out by *cPP. The pointer *cPP is
+ advanced to the character following the indirect operand on success, or
+ has an unspecified value on failure.
+
+ cPP Pointer to pointer to string beginning
+ with the operand
+
+ prefixp Pointer to structure containing an
+ instruction prefix
+
+ Returns 1 iff a correct indirect operand is found. */
+
+static int
+get_3op_or_dip_prefix_op (char **cPP, struct cris_prefix *prefixp)
+{
+ int reg_number;
+
+ if (**cPP != '[')
+ /* We must have a '[' or it's a clean failure. */
+ return 0;
+
+ /* Eat the first '['. */
+ (*cPP)++;
+
+ if (**cPP == '[')
+ {
+ /* A second '[', so this must be double-indirect mode. */
+ (*cPP)++;
+ prefixp->kind = PREFIX_DIP;
+ prefixp->opcode = DIP_OPCODE;
+
+ /* Get the register or fail entirely. */
+ if (! get_gen_reg (cPP, &reg_number))
+ return 0;
+ else
+ {
+ prefixp->opcode |= reg_number /* << 0 */ ;
+ if (**cPP == '+')
+ {
+ /* Since we found a '+', this must be double-indirect
+ autoincrement mode. */
+ (*cPP)++;
+ prefixp->opcode |= AUTOINCR_BIT << 8;
+ }
+
+ /* There's nothing particular to do, if this was a
+ double-indirect *without* autoincrement. */
+ }
+
+ /* Check the first ']'. The second one is checked at the end. */
+ if (**cPP != ']')
+ return 0;
+
+ /* Eat the first ']', so we'll be looking at a second ']'. */
+ (*cPP)++;
+ }
+ /* No second '['. Then we should have a register here, making
+ it "[rN". */
+ else if (get_gen_reg (cPP, &prefixp->base_reg_number))
+ {
+ /* This must be indexed or offset mode: "[rN+I]" or
+ "[rN+rM.S]" or "[rN+[rM].S]" or "[rN+[rM+].S]". */
+ if (**cPP == '+')
+ {
+ int index_reg_number;
+
+ (*cPP)++;
+
+ if (**cPP == '[')
+ {
+ /* This is "[rx+["... Expect a register next. */
+ int size_bits;
+ (*cPP)++;
+
+ if (!get_gen_reg (cPP, &index_reg_number))
+ return 0;
+
+ prefixp->kind = PREFIX_BDAP;
+ prefixp->opcode
+ = (BDAP_INDIR_OPCODE
+ + (prefixp->base_reg_number << 12)
+ + index_reg_number);
+
+ /* We've seen "[rx+[ry", so check if this is
+ autoincrement. */
+ if (**cPP == '+')
+ {
+ /* Yep, now at "[rx+[ry+". */
+ (*cPP)++;
+ prefixp->opcode |= AUTOINCR_BIT << 8;
+ }
+ /* If it wasn't autoincrement, we don't need to
+ add anything. */
+
+ /* Check a first closing ']': "[rx+[ry]" or
+ "[rx+[ry+]". */
+ if (**cPP != ']')
+ return 0;
+ (*cPP)++;
+
+ /* Now expect a size modifier ".S". */
+ if (! get_bwd_size_modifier (cPP, &size_bits))
+ return 0;
+
+ prefixp->opcode |= size_bits << 4;
+
+ /* Ok, all interesting stuff has been seen:
+ "[rx+[ry+].S" or "[rx+[ry].S". We only need to
+ expect a final ']', which we'll do in a common
+ closing session. */
+ }
+ /* Seen "[rN+", but not a '[', so check if we have a
+ register. */
+ else if (get_gen_reg (cPP, &index_reg_number))
+ {
+ /* This is indexed mode: "[rN+rM.S]" or
+ "[rN+rM.S+]". */
+ int size_bits;
+ prefixp->kind = PREFIX_BIAP;
+ prefixp->opcode
+ = (BIAP_OPCODE
+ | 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;
+ else
+ /* Size found. Add that piece and drop down to
+ the common checking of the closing ']'. */
+ prefixp->opcode |= size_bits << 4;
+ }
+ /* Seen "[rN+", but not a '[' or a register, so then
+ it must be a constant "I".
+
+ As a quality of implementation improvement, we check for a
+ closing ']', like in an erroneous "[rN+]". If we don't,
+ the expression parser will emit a confusing "bad
+ expression" when it sees the ']', probably because it
+ doesn't like seeing no expression. */
+ else if (**cPP != ']' && cris_get_expression (cPP, &prefixp->expr))
+ {
+ /* Expression found, so fill in the bits of offset
+ mode and drop down to check the closing ']'. */
+ prefixp->kind = PREFIX_BDAP_IMM;
+
+ /* We tentatively put an opcode corresponding to a 32-bit
+ operand here, although it may be relaxed when there's no
+ PIC specifier for the operand. */
+ prefixp->opcode
+ = (BDAP_INDIR_OPCODE
+ | (prefixp->base_reg_number << 12)
+ | (AUTOINCR_BIT << 8)
+ | (2 << 4)
+ | REG_PC /* << 0 */);
+
+ /* This can have a PIC suffix, specifying reloc type to use. */
+ if ((pic || tls) && **cPP == RELOC_SUFFIX_CHAR)
+ {
+ unsigned int relocsize;
+
+ cris_get_reloc_suffix (cPP, &prefixp->reloc, &prefixp->expr);
+
+ /* Tweak the size of the immediate operand in the prefix
+ opcode if it isn't what we set. */
+ relocsize = cris_get_specified_reloc_size (prefixp->reloc);
+ if (relocsize != 4)
+ prefixp->opcode
+ = ((prefixp->opcode & ~(3 << 4))
+ | ((relocsize >> 1) << 4));
+ }
+ }
+ else
+ /* Nothing valid here: lose. */
+ return 0;
+ }
+ /* Seen "[rN" but no '+', so check if it's a '-'. */
+ else if (**cPP == '-')
+ {
+ /* Yep, we must have offset mode. */
+ if (! cris_get_expression (cPP, &prefixp->expr))
+ /* No expression, so we lose. */
+ return 0;
+ else
+ {
+ /* Expression found to make this offset mode, so
+ fill those bits and drop down to check the
+ closing ']'.
+
+ Note that we don't allow a PIC suffix for
+ an operand with a minus sign like this. */
+ prefixp->kind = PREFIX_BDAP_IMM;
+ }
+ }
+ else
+ {
+ /* We've seen "[rN", but not '+' or '-'; rather a ']'.
+ Hmm. Normally this is a simple indirect mode that we
+ shouldn't match, but if we expect ']', then we have a
+ zero offset, so it can be a three-address-operand,
+ like "[rN],rO,rP", thus offset mode.
+
+ Don't eat the ']', that will be done in the closing
+ ceremony. */
+ prefixp->expr.X_op = O_constant;
+ prefixp->expr.X_add_number = 0;
+ prefixp->expr.X_add_symbol = NULL;
+ prefixp->expr.X_op_symbol = NULL;
+ prefixp->kind = PREFIX_BDAP_IMM;
+ }
+ }
+ /* A '[', but no second '[', and no register. Check if we
+ have an expression, making this "[I]" for a double-indirect
+ prefix. */
+ else if (cris_get_expression (cPP, &prefixp->expr))
+ {
+ /* Expression found, the so called absolute mode for a
+ double-indirect prefix on PC. */
+ prefixp->kind = PREFIX_DIP;
+ prefixp->opcode = DIP_OPCODE | (AUTOINCR_BIT << 8) | REG_PC;
+ prefixp->reloc = BFD_RELOC_32;
+
+ /* For :GD and :IE, it makes sense to have TLS specifiers here. */
+ if ((pic || tls) && **cPP == RELOC_SUFFIX_CHAR)
+ cris_get_reloc_suffix (cPP, &prefixp->reloc, &prefixp->expr);
+ }
+ else
+ /* Neither '[' nor register nor expression. We lose. */
+ return 0;
+
+ /* We get here as a closing ceremony to a successful match. We just
+ need to check the closing ']'. */
+ if (**cPP != ']')
+ /* Oops. Close but no air-polluter. */
+ return 0;
+
+ /* Don't forget to consume that ']', before returning in glory. */
+ (*cPP)++;
+ return 1;
+}
+
+/* Get an expression from the string pointed out by *cPP.
+ The pointer *cPP is advanced to the character following the expression
+ on a success, or retains its original value otherwise.
+
+ cPP Pointer to pointer to string beginning with the expression.
+
+ exprP Pointer to structure containing the expression.
+
+ Return 1 iff a correct expression is found. */
+
+static int
+cris_get_expression (char **cPP, expressionS *exprP)
+{
+ char *saved_input_line_pointer;
+
+ /* The "expression" function expects to find an expression at the
+ global variable input_line_pointer, so we have to save it to give
+ the impression that we don't fiddle with global variables. */
+ saved_input_line_pointer = input_line_pointer;
+ input_line_pointer = *cPP;
+
+ /* Avoid a common error, confusing addressing modes. Beware that the
+ call to expression below does not signal that error; it treats []
+ as parentheses, unless #define NEED_INDEX_OPERATOR in which case it
+ gives them other confusing semantics rather than plain outlawing
+ them, which is what we want. */
+ if (*input_line_pointer == '[')
+ {
+ input_line_pointer = saved_input_line_pointer;
+ return 0;
+ }
+
+ expression (exprP);
+ if (exprP->X_op == O_illegal || exprP->X_op == O_absent)
+ {
+ input_line_pointer = saved_input_line_pointer;
+ return 0;
+ }
+
+ /* Everything seems to be fine, just restore the global
+ input_line_pointer and say we're successful. */
+ *cPP = input_line_pointer;
+ input_line_pointer = saved_input_line_pointer;
+ return 1;
+}
+
+/* Get a sequence of flag characters from *spp. The pointer *cPP is
+ advanced to the character following the expression. The flag
+ characters are consecutive, no commas or spaces.
+
+ cPP Pointer to pointer to string beginning with the expression.
+
+ flagp Pointer to int to return the flags expression.
+
+ Return 1 iff a correct flags expression is found. */
+
+static int
+get_flags (char **cPP, int *flagsp)
+{
+ for (;;)
+ {
+ switch (**cPP)
+ {
+ case 'd':
+ case 'D':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v0_3,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x80;
+ break;
+
+ case 'm':
+ case 'M':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v8_10,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x80;
+ break;
+
+ case 'e':
+ case 'E':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v0_3,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x40;
+ break;
+
+ case 'b':
+ case 'B':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v8_10,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x40;
+ break;
+
+ case 'p':
+ case 'P':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v32p,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x80;
+ break;
+
+ case 'u':
+ case 'U':
+ if (! cris_insn_ver_valid_for_arch (cris_ver_v32p,
+ cris_arch))
+ return 0;
+ *flagsp |= 0x40;
+ break;
+
+ case 'i':
+ case 'I':
+ *flagsp |= 0x20;
+ break;
+
+ case 'x':
+ case 'X':
+ *flagsp |= 0x10;
+ break;
+
+ case 'n':
+ case 'N':
+ *flagsp |= 0x8;
+ break;
+
+ case 'z':
+ case 'Z':
+ *flagsp |= 0x4;
+ break;
+
+ case 'v':
+ case 'V':
+ *flagsp |= 0x2;
+ break;
+
+ case 'c':
+ case 'C':
+ *flagsp |= 1;
+ break;
+
+ default:
+ /* We consider this successful if we stop at a comma or
+ whitespace. Anything else, and we consider it a failure. */
+ if (**cPP != ','
+ && **cPP != 0
+ && ! ISSPACE (**cPP))
+ return 0;
+ else
+ return 1;
+ }
+
+ /* Don't forget to consume each flag character. */
+ (*cPP)++;
+ }
+}
+
+/* Generate code and fixes for a BDAP prefix.
+ For v32, this handles ADDOQ because thankfully the opcodes are the
+ same.
+
+ base_regno Int containing the base register number.
+
+ exprP Pointer to structure containing the offset expression. */
+
+static void
+gen_bdap (int base_regno, expressionS *exprP)
+{
+ unsigned int opcode;
+ char *opcodep;
+
+ /* Put out the prefix opcode; assume quick immediate mode at first. */
+ opcode = BDAP_QUICK_OPCODE | (base_regno << 12);
+ opcodep = cris_insn_first_word_frag ();
+ md_number_to_chars (opcodep, opcode, 2);
+
+ if (exprP->X_op == O_constant)
+ {
+ /* We have an absolute expression that we know the size of right
+ now. */
+ long int value;
+ int size;
+
+ value = exprP->X_add_number;
+ if (value < -32768 || value > 32767)
+ /* Outside range for a "word", make it a dword. */
+ size = 2;
+ else
+ /* Assume "word" size. */
+ size = 1;
+
+ /* If this is a signed-byte value, we can fit it into the prefix
+ insn itself. */
+ if (value >= -128 && value <= 127)
+ opcodep[0] = value;
+ else
+ {
+ /* This is a word or dword displacement, which will be put in a
+ word or dword after the prefix. */
+ char *p;
+
+ opcodep[0] = BDAP_PC_LOW + (size << 4);
+ opcodep[1] &= 0xF0;
+ opcodep[1] |= BDAP_INCR_HIGH;
+ p = frag_more (1 << size);
+ md_number_to_chars (p, value, 1 << size);
+ }
+ }
+ else
+ {
+ /* Handle complex expressions. */
+ valueT addvalue
+ = SIMPLE_EXPR (exprP) ? exprP->X_add_number : 0;
+ symbolS *sym
+ = (SIMPLE_EXPR (exprP)
+ ? exprP->X_add_symbol : make_expr_symbol (exprP));
+
+ /* The expression is not defined yet but may become absolute. We
+ make it a relocation to be relaxed. */
+ frag_var (rs_machine_dependent, 4, 0,
+ ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_UNDF),
+ sym, addvalue, opcodep);
+ }
+}
+
+/* Encode a branch displacement in the range -256..254 into the form used
+ by CRIS conditional branch instructions.
+
+ offset The displacement value in bytes. */
+
+static int
+branch_disp (int offset)
+{
+ int disp;
+
+ /* Adjust all short branch offsets here. */
+ if (cris_arch == arch_crisv32 || cris_arch == arch_cris_common_v10_v32)
+ offset += 2;
+
+ disp = offset & 0xFE;
+
+ if (offset < 0)
+ disp |= 1;
+
+ return disp;
+}
+
+/* Generate code and fixes for a 32-bit conditional branch instruction
+ created by "extending" an existing 8-bit branch instruction.
+
+ opcodep Pointer to the word containing the original 8-bit branch
+ instruction.
+
+ writep Pointer to "extension area" following the first instruction
+ word.
+
+ fragP Pointer to the frag containing the instruction.
+
+ add_symP, Parts of the destination address expression.
+ sub_symP,
+ add_num. */
+
+static void
+gen_cond_branch_32 (char *opcodep, char *writep, fragS *fragP,
+ symbolS *add_symP, symbolS *sub_symP, long int add_num)
+{
+ int nop_opcode;
+ int opc_offset;
+ int branch_offset;
+
+ if (cris_arch == arch_crisv32)
+ {
+ nop_opcode = NOP_OPCODE_V32;
+ opc_offset = 10;
+ branch_offset = -2 - 8;
+ }
+ else if (pic)
+ {
+ nop_opcode = NOP_OPCODE;
+ opc_offset = 10;
+ branch_offset = -2 - 8;
+ }
+ else
+ {
+ nop_opcode = NOP_OPCODE;
+ opc_offset = 8;
+ branch_offset = -2 - 6;
+ }
+
+ /* We should never get here for compatibility mode. */
+ if (cris_arch == arch_cris_common_v10_v32)
+ as_fatal (_("Calling gen_cond_branch_32 for .arch common_v10_v32\n"));
+
+ if (warn_for_branch_expansion)
+ as_warn_where (fragP->fr_file, fragP->fr_line,
+ _("32-bit conditional branch generated"));
+
+ /* Here, writep points to what will be opcodep + 2. First, we change
+ the actual branch in opcodep[0] and opcodep[1], so that in the
+ final insn, it will look like:
+ opcodep+10: Bcc .-6
+
+ This means we don't have to worry about changing the opcode or
+ messing with the delay-slot instruction. So, we move it to last in
+ the "extended" branch, and just change the displacement. Admittedly,
+ it's not the optimal extended construct, but we should get this
+ rarely enough that it shouldn't matter. */
+
+ writep[opc_offset] = branch_disp (branch_offset);
+ writep[opc_offset + 1] = opcodep[1];
+
+ /* Then, we change the branch to an unconditional branch over the
+ extended part, to the new location of the Bcc:
+ opcodep: BA .+10
+ opcodep+2: NOP
+
+ Note that these two writes are to currently different locations,
+ merged later. */
+
+ md_number_to_chars (opcodep, BA_QUICK_OPCODE
+ + (cris_arch == arch_crisv32 ? 12 : (pic ? 10 : 8)),
+ 2);
+ md_number_to_chars (writep, nop_opcode, 2);
+
+ /* Then the extended thing, the 32-bit jump insn.
+ opcodep+4: JUMP [PC+]
+ or, in the PIC case,
+ opcodep+4: MOVE [PC=PC+N],P0. */
+
+ md_number_to_chars (writep + 2,
+ cris_arch == arch_crisv32
+ ? BA_DWORD_OPCODE
+ : (pic ? MOVE_PC_INCR_OPCODE_PREFIX
+ : JUMP_PC_INCR_OPCODE), 2);
+
+ /* We have to fill in the actual value too.
+ opcodep+6: .DWORD
+ This is most probably an expression, but we can cope with an absolute
+ value too. FIXME: Testcase needed with and without pic. */
+
+ if (add_symP == NULL && sub_symP == NULL)
+ {
+ /* An absolute address. */
+ if (pic || cris_arch == arch_crisv32)
+ fix_new (fragP, writep + 4 - fragP->fr_literal, 4,
+ section_symbol (absolute_section),
+ add_num
+ + (cris_arch == arch_crisv32 ? 6 : 0),
+ 1, BFD_RELOC_32_PCREL);
+ else
+ md_number_to_chars (writep + 4, add_num, 4);
+ }
+ else
+ {
+ if (sub_symP != NULL)
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("Complex expression not supported"));
+
+ /* Not absolute, we have to make it a frag for later evaluation. */
+ fix_new (fragP, writep + 4 - fragP->fr_literal, 4, add_symP,
+ add_num + (cris_arch == arch_crisv32 ? 6 : 0),
+ pic || cris_arch == arch_crisv32 ? 1 : 0,
+ pic || cris_arch == arch_crisv32
+ ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+ }
+
+ if (cris_arch == arch_crisv32)
+ /* Follow it with a "NOP" for CRISv32. */
+ md_number_to_chars (writep + 8, NOP_OPCODE_V32, 2);
+ else if (pic)
+ /* ...and the rest of the move-opcode for pre-v32 PIC. */
+ md_number_to_chars (writep + 8, MOVE_PC_INCR_OPCODE_SUFFIX, 2);
+}
+
+/* Get the size of an immediate-reloc in bytes. Only valid for
+ specified relocs (TLS, PIC). */
+
+static unsigned int
+cris_get_specified_reloc_size (bfd_reloc_code_real_type reloc)
+{
+ return
+ reloc == BFD_RELOC_CRIS_16_GOTPLT
+ || reloc == BFD_RELOC_CRIS_16_GOT
+ || reloc == BFD_RELOC_CRIS_16_GOT_GD
+ || reloc == BFD_RELOC_CRIS_16_DTPREL
+ || reloc == BFD_RELOC_CRIS_16_GOT_TPREL
+ || reloc == BFD_RELOC_CRIS_16_TPREL
+ ? 2 : 4;
+}
+
+/* Store a reloc type at *RELOCP corresponding to the PIC suffix at *CPP.
+ Adjust *EXPRP with any addend found after the PIC suffix. */
+
+static void
+cris_get_reloc_suffix (char **cPP, bfd_reloc_code_real_type *relocp,
+ expressionS *exprP)
+{
+ char *s = *cPP;
+ unsigned int i;
+ expressionS const_expr;
+
+ const struct pic_suffixes_struct
+ {
+ const char *const suffix;
+ unsigned int len;
+ bfd_reloc_code_real_type reloc;
+ bfd_boolean pic_p;
+ bfd_boolean tls_p;
+ } pic_suffixes[] =
+ {
+#undef PICMAP
+#define PICMAP(s, r) {s, sizeof (s) - 1, r, TRUE, FALSE}
+#define PICTLSMAP(s, r) {s, sizeof (s) - 1, r, TRUE, TRUE}
+#define TLSMAP(s, r) {s, sizeof (s) - 1, r, FALSE, TRUE}
+ /* Keep this in order with longest unambiguous prefix first. */
+ PICMAP ("GOTPLT16", BFD_RELOC_CRIS_16_GOTPLT),
+ PICMAP ("GOTPLT", BFD_RELOC_CRIS_32_GOTPLT),
+ PICMAP ("PLTG", BFD_RELOC_CRIS_32_PLT_GOTREL),
+ PICMAP ("PLT", BFD_RELOC_CRIS_32_PLT_PCREL),
+ PICMAP ("GOTOFF", BFD_RELOC_CRIS_32_GOTREL),
+ PICMAP ("GOT16", BFD_RELOC_CRIS_16_GOT),
+ PICMAP ("GOT", BFD_RELOC_CRIS_32_GOT),
+ PICTLSMAP ("GDGOTREL16", BFD_RELOC_CRIS_16_GOT_GD),
+ PICTLSMAP ("GDGOTREL", BFD_RELOC_CRIS_32_GOT_GD),
+ TLSMAP ("GD", BFD_RELOC_CRIS_32_GD),
+ PICTLSMAP ("DTPREL16", BFD_RELOC_CRIS_16_DTPREL),
+ PICTLSMAP ("DTPREL", BFD_RELOC_CRIS_32_DTPREL),
+ TLSMAP ("IE", BFD_RELOC_CRIS_32_IE),
+ PICTLSMAP ("TPOFFGOT16", BFD_RELOC_CRIS_16_GOT_TPREL),
+ PICTLSMAP ("TPOFFGOT", BFD_RELOC_CRIS_32_GOT_TPREL),
+ TLSMAP ("TPOFF16", BFD_RELOC_CRIS_16_TPREL),
+ TLSMAP ("TPOFF", BFD_RELOC_CRIS_32_TPREL)
+ };
+
+ /* We've already seen the ':', so consume it. */
+ s++;
+
+ for (i = 0; i < sizeof (pic_suffixes)/sizeof (pic_suffixes[0]); i++)
+ {
+ if (strncmp (s, pic_suffixes[i].suffix, pic_suffixes[i].len) == 0
+ && ! is_part_of_name (s[pic_suffixes[i].len])
+ /* PIC and non-PIC relocations are exclusive. */
+ && (pic != 0) == (pic_suffixes[i].pic_p != 0)
+ /* But TLS can be active for non-TLS relocations too. */
+ && (pic_suffixes[i].tls_p == 0 || tls))
+ {
+ /* We have a match. Consume the suffix and set the relocation
+ type. */
+ s += pic_suffixes[i].len;
+
+ /* There can be a constant term appended. If so, we will add it
+ to *EXPRP. */
+ if (*s == '+' || *s == '-')
+ {
+ if (! cris_get_expression (&s, &const_expr))
+ /* There was some kind of syntax error. Bail out. */
+ break;
+
+ /* Allow complex expressions as the constant part. It still
+ has to be an assembly-time constant or there will be an
+ error emitting the reloc. This makes the PIC qualifiers
+ idempotent; foo:GOTOFF+32 == foo+32:GOTOFF. The former we
+ recognize here; the latter is parsed in the incoming
+ expression. */
+ exprP->X_add_symbol = make_expr_symbol (exprP);
+ exprP->X_op = O_add;
+ exprP->X_add_number = 0;
+ exprP->X_op_symbol = make_expr_symbol (&const_expr);
+ }
+
+ *relocp = pic_suffixes[i].reloc;
+ *cPP = s;
+ return;
+ }
+ }
+
+ /* No match. Don't consume anything; fall back and there will be a
+ syntax error. */
+}
+
+/* This *could* have been:
+
+ 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.
+
+ type A character from FLTCHARS that describes what kind of
+ floating-point number is wanted.
+
+ litp A pointer to an array that the result should be stored in.
+
+ sizep A pointer to an integer where the size of the result is stored.
+
+ But we don't support floating point constants in assembly code *at all*,
+ since it's suboptimal and just opens up bug opportunities. GCC emits
+ the bit patterns as hex. All we could do here is to emit what GCC
+ would have done in the first place. *Nobody* writes floating-point
+ code as assembly code, but if they do, they should be able enough to
+ find out the correct bit patterns and use them. */
+
+char *
+md_atof (int type ATTRIBUTE_UNUSED, char *litp ATTRIBUTE_UNUSED,
+ int *sizep ATTRIBUTE_UNUSED)
+{
+ /* FIXME: Is this function mentioned in the internals.texi manual? If
+ not, add it. */
+ return _("Bad call to md_atof () - floating point formats are not supported");
+}
+
+/* Turn a number as a fixS * into a series of bytes that represents the
+ number on the target machine. The purpose of this procedure is the
+ same as that of md_number_to_chars but this procedure is supposed to
+ handle general bit field fixes and machine-dependent fixups.
+
+ bufp Pointer to an array where the result should be stored.
+
+ val The value to store.
+
+ n The number of bytes in "val" that should be stored.
+
+ fixP The fix to be applied to the bit field starting at bufp.
+
+ seg The segment containing this number. */
+
+static void
+cris_number_to_imm (char *bufp, long val, int n, fixS *fixP, segT seg)
+{
+ segT sym_seg;
+
+ know (n <= 4);
+ know (fixP);
+
+ /* We put the relative "vma" for the other segment for inter-segment
+ relocations in the object data to stay binary "compatible" (with an
+ uninteresting old version) for the relocation.
+ Maybe delete some day. */
+ if (fixP->fx_addsy
+ && (sym_seg = S_GET_SEGMENT (fixP->fx_addsy)) != seg)
+ val += sym_seg->vma;
+
+ if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+ switch (fixP->fx_r_type)
+ {
+ /* These must be fully resolved when getting here. */
+ case BFD_RELOC_16_PCREL:
+ case BFD_RELOC_8_PCREL:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("PC-relative relocation must be trivially resolved"));
+ default:
+ ;
+ }
+
+ /* Only use the computed value for old-arch binaries. For all
+ others, where we're going to output a relocation, put 0 in the
+ code. */
+ if (cris_arch != arch_cris_any_v0_v10
+ && (fixP->fx_addsy != NULL || fixP->fx_pcrel))
+ val = 0;
+
+ switch (fixP->fx_r_type)
+ {
+ /* Ditto here, we put the addend into the object code as
+ well as the reloc addend. Keep it that way for now, to simplify
+ regression tests on the object file contents. FIXME: Seems
+ uninteresting now that we have a test suite. */
+
+ case BFD_RELOC_CRIS_32_GOT_GD:
+ case BFD_RELOC_CRIS_16_GOT_GD:
+ case BFD_RELOC_CRIS_32_GD:
+ case BFD_RELOC_CRIS_32_IE:
+ case BFD_RELOC_CRIS_32_DTPREL:
+ case BFD_RELOC_CRIS_16_DTPREL:
+ case BFD_RELOC_CRIS_32_GOT_TPREL:
+ case BFD_RELOC_CRIS_16_GOT_TPREL:
+ case BFD_RELOC_CRIS_32_TPREL:
+ case BFD_RELOC_CRIS_16_TPREL:
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (IS_ELF && fixP->fx_addsy != NULL)
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+#endif
+ /* Fall through. */
+
+ case BFD_RELOC_CRIS_16_GOT:
+ case BFD_RELOC_CRIS_32_GOT:
+ case BFD_RELOC_CRIS_32_GOTREL:
+ case BFD_RELOC_CRIS_16_GOTPLT:
+ case BFD_RELOC_CRIS_32_GOTPLT:
+ case BFD_RELOC_CRIS_32_PLT_GOTREL:
+ case BFD_RELOC_CRIS_32_PLT_PCREL:
+ /* We don't want to put in any kind of non-zero bits in the data
+ being relocated for these. */
+ md_number_to_chars (bufp, 0, n);
+ break;
+
+ case BFD_RELOC_32_PCREL:
+ /* If this one isn't fully resolved, we don't want to put non-zero
+ in the object. */
+ if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+ val = 0;
+
+ /* Fall through. */
+ case BFD_RELOC_32:
+ /* No use having warnings here, since most hosts have a 32-bit type
+ for "long" (which will probably change soon, now that I wrote
+ this). */
+ bufp[3] = (val >> 24) & 0xFF;
+ bufp[2] = (val >> 16) & 0xFF;
+ bufp[1] = (val >> 8) & 0xFF;
+ bufp[0] = val & 0xFF;
+ break;
+
+ /* FIXME: The 16 and 8-bit cases should have a way to check
+ whether a signed or unsigned (or any signedness) number is
+ accepted. */
+
+ case BFD_RELOC_16:
+ case BFD_RELOC_16_PCREL:
+ if (val > 0xffff || val < -32768)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 16 bit range: %ld"), val);
+ bufp[1] = (val >> 8) & 0xFF;
+ bufp[0] = val & 0xFF;
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_16:
+ if (val > 32767 || val < -32768)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 16 bit signed range: %ld"), val);
+ bufp[1] = (val >> 8) & 0xFF;
+ bufp[0] = val & 0xFF;
+ break;
+
+ case BFD_RELOC_8:
+ case BFD_RELOC_8_PCREL:
+ if (val > 255 || val < -128)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("Value not in 8 bit range: %ld"), val);
+ bufp[0] = val & 0xFF;
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_8:
+ if (val > 127 || val < -128)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 8 bit signed range: %ld"), val);
+ bufp[0] = val & 0xFF;
+ break;
+
+ case BFD_RELOC_CRIS_LAPCQ_OFFSET:
+ /* FIXME: Test-cases for out-of-range values. Probably also need
+ to use as_bad_where. */
+ case BFD_RELOC_CRIS_UNSIGNED_4:
+ if (val > 15 || val < 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 4 bit unsigned range: %ld"), val);
+ bufp[0] |= val & 0x0F;
+ break;
+
+ case BFD_RELOC_CRIS_UNSIGNED_5:
+ if (val > 31 || val < 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 5 bit unsigned range: %ld"), val);
+ bufp[0] |= val & 0x1F;
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_6:
+ if (val > 31 || val < -32)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 6 bit range: %ld"), val);
+ bufp[0] |= val & 0x3F;
+ break;
+
+ case BFD_RELOC_CRIS_UNSIGNED_6:
+ if (val > 63 || val < 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Value not in 6 bit unsigned range: %ld"), val);
+ bufp[0] |= val & 0x3F;
+ break;
+
+ case BFD_RELOC_CRIS_BDISP8:
+ bufp[0] = branch_disp (val);
+ break;
+
+ case BFD_RELOC_NONE:
+ /* May actually happen automatically. For example at broken
+ words, if the word turns out not to be broken.
+ FIXME: When? Which testcase? */
+ if (! fixP->fx_addsy)
+ md_number_to_chars (bufp, val, n);
+ break;
+
+ case BFD_RELOC_VTABLE_INHERIT:
+ /* This borrowed from tc-ppc.c on a whim. */
+ if (fixP->fx_addsy
+ && !S_IS_DEFINED (fixP->fx_addsy)
+ && !S_IS_WEAK (fixP->fx_addsy))
+ S_SET_WEAK (fixP->fx_addsy);
+ /* Fall through. */
+
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixP->fx_done = 0;
+ break;
+
+ default:
+ BAD_CASE (fixP->fx_r_type);
+ }
+}
+
+/* Processes machine-dependent command line options. Called once for
+ each option on the command line that the machine-independent part of
+ GAS does not understand. */
+
+int
+md_parse_option (int arg, char *argp ATTRIBUTE_UNUSED)
+{
+ switch (arg)
+ {
+ case 'H':
+ case 'h':
+ printf (_("Please use --help to see usage and options for this assembler.\n"));
+ md_show_usage (stdout);
+ exit (EXIT_SUCCESS);
+
+ case 'N':
+ warn_for_branch_expansion = 1;
+ break;
+
+ 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"));
+ else
+ symbols_have_leading_underscore = FALSE;
+ break;
+
+ case OPTION_US:
+ demand_register_prefix = FALSE;
+ symbols_have_leading_underscore = TRUE;
+ break;
+
+ case OPTION_PIC:
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+ as_bad (_("--pic is invalid for this object format"));
+ pic = TRUE;
+ if (cris_arch != arch_crisv32)
+ md_long_jump_size = cris_any_v0_v10_long_jump_size_pic;
+ else
+ md_long_jump_size = crisv32_long_jump_size;
+ break;
+
+ case OPTION_ARCH:
+ {
+ char *str = argp;
+ enum cris_archs argarch = cris_arch_from_string (&str);
+
+ if (argarch == arch_cris_unknown)
+ as_bad (_("invalid <arch> in --march=<arch>: %s"), argp);
+ else
+ cris_arch = argarch;
+
+ if (argarch == arch_crisv32)
+ {
+ err_for_dangerous_mul_placement = 0;
+ md_long_jump_size = crisv32_long_jump_size;
+ }
+ else
+ {
+ if (pic)
+ md_long_jump_size = cris_any_v0_v10_long_jump_size_pic;
+ else
+ md_long_jump_size = cris_any_v0_v10_long_jump_size;
+ }
+ }
+ break;
+
+ case OPTION_MULBUG_ABORT_OFF:
+ err_for_dangerous_mul_placement = 0;
+ break;
+
+ case OPTION_MULBUG_ABORT_ON:
+ err_for_dangerous_mul_placement = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Round up a section size to the appropriate boundary. */
+valueT
+md_section_align (segT segment, valueT size)
+{
+ /* Round all sects to multiple of 4, except the bss section, which
+ we'll round to word-size.
+
+ FIXME: Check if this really matters. All sections should be
+ rounded up, and all sections should (optionally) be assumed to be
+ dword-aligned, it's just that there is actual usage of linking to a
+ multiple of two. */
+ if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
+ {
+ if (segment == bss_section)
+ return (size + 1) & ~1;
+ return (size + 3) & ~3;
+ }
+ else
+ {
+ /* FIXME: Is this wanted? It matches the testsuite, but that's not
+ really a valid reason. */
+ if (segment == text_section)
+ return (size + 3) & ~3;
+ }
+
+ return size;
+}
+
+/* Generate a machine-dependent relocation. */
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
+{
+ arelent *relP;
+ bfd_reloc_code_real_type code;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_CRIS_SIGNED_8:
+ code = BFD_RELOC_8;
+ break;
+
+ case BFD_RELOC_CRIS_SIGNED_16:
+ code = BFD_RELOC_16;
+ break;
+
+ case BFD_RELOC_CRIS_16_GOT:
+ case BFD_RELOC_CRIS_32_GOT:
+ case BFD_RELOC_CRIS_16_GOTPLT:
+ case BFD_RELOC_CRIS_32_GOTPLT:
+ case BFD_RELOC_CRIS_32_GOTREL:
+ case BFD_RELOC_CRIS_32_PLT_GOTREL:
+ case BFD_RELOC_CRIS_32_PLT_PCREL:
+ case BFD_RELOC_32:
+ case BFD_RELOC_32_PCREL:
+ case BFD_RELOC_16:
+ case BFD_RELOC_8:
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_CRIS_UNSIGNED_8:
+ case BFD_RELOC_CRIS_UNSIGNED_16:
+ case BFD_RELOC_CRIS_LAPCQ_OFFSET:
+ case BFD_RELOC_CRIS_32_GOT_GD:
+ case BFD_RELOC_CRIS_16_GOT_GD:
+ case BFD_RELOC_CRIS_32_GD:
+ case BFD_RELOC_CRIS_32_IE:
+ case BFD_RELOC_CRIS_32_DTPREL:
+ case BFD_RELOC_CRIS_16_DTPREL:
+ case BFD_RELOC_CRIS_32_GOT_TPREL:
+ case BFD_RELOC_CRIS_16_GOT_TPREL:
+ case BFD_RELOC_CRIS_32_TPREL:
+ case BFD_RELOC_CRIS_16_TPREL:
+ code = fixP->fx_r_type;
+ break;
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant"));
+ return 0;
+ }
+
+ relP = (arelent *) xmalloc (sizeof (arelent));
+ gas_assert (relP != 0);
+ relP->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
+ relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
+
+ relP->addend = fixP->fx_offset;
+
+ /* This is the standard place for KLUDGEs to work around bugs in
+ bfd_install_relocation (first such note in the documentation
+ appears with binutils-2.8).
+
+ That function bfd_install_relocation does the wrong thing with
+ putting stuff into the addend of a reloc (it should stay out) for a
+ weak symbol. The really bad thing is that it adds the
+ "segment-relative offset" of the symbol into the reloc. In this
+ case, the reloc should instead be relative to the symbol with no
+ other offset than the assembly code shows; and since the symbol is
+ weak, any local definition should be ignored until link time (or
+ thereafter).
+ To wit: weaksym+42 should be weaksym+42 in the reloc,
+ not weaksym+(offset_from_segment_of_local_weaksym_definition)
+
+ To "work around" this, we subtract the segment-relative offset of
+ "known" weak symbols. This evens out the extra offset.
+
+ That happens for a.out but not for ELF, since for ELF,
+ bfd_install_relocation uses the "special function" field of the
+ howto, and does not execute the code that needs to be undone. */
+
+ if (OUTPUT_FLAVOR == bfd_target_aout_flavour
+ && fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)
+ && ! bfd_is_und_section (S_GET_SEGMENT (fixP->fx_addsy)))
+ {
+ relP->addend -= S_GET_VALUE (fixP->fx_addsy);
+ }
+
+ relP->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (! relP->howto)
+ {
+ const char *name;
+
+ name = S_GET_NAME (fixP->fx_addsy);
+ if (name == NULL)
+ name = _("<unknown>");
+ as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
+ name, bfd_get_reloc_code_name (code));
+ }
+
+ return relP;
+}
+
+/* Machine-dependent usage-output. */
+
+void
+md_show_usage (FILE *stream)
+{
+ /* The messages are formatted to line up with the generic options. */
+ 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"));
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ fprintf (stream, "%s",
+ _(" --pic Enable generation of position-independent code.\n"));
+#endif
+ fprintf (stream, "%s",
+ _(" --march=<arch> Generate code for <arch>. Valid choices for <arch>\n\
+ are v0_v10, v10, v32 and common_v10_v32.\n"));
+}
+
+/* Apply a fixS (fixup of an instruction or data that we didn't have
+ enough info to complete immediately) to the data in a frag. */
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
+{
+ /* This assignment truncates upper bits if valueT is 64 bits (as with
+ --enable-64-bit-bfd), which is fine here, though we cast to avoid
+ any compiler warnings. */
+ long val = (long) *valP;
+ char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+
+ if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
+ fixP->fx_done = 1;
+
+ if (fixP->fx_bit_fixP || fixP->fx_im_disp != 0)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("Invalid relocation"));
+ fixP->fx_done = 1;
+ }
+ else
+ {
+ /* We can't actually support subtracting a symbol. */
+ if (fixP->fx_subsy != (symbolS *) NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("expression too complex"));
+
+ /* This operand-type is scaled. */
+ if (fixP->fx_r_type == BFD_RELOC_CRIS_LAPCQ_OFFSET)
+ val /= 2;
+ cris_number_to_imm (buf, val, fixP->fx_size, fixP, seg);
+ }
+}
+
+/* All relocations are relative to the location just after the fixup;
+ the address of the fixup plus its size. */
+
+long
+md_pcrel_from (fixS *fixP)
+{
+ valueT addr = fixP->fx_where + fixP->fx_frag->fr_address;
+
+ /* FIXME: We get here only at the end of assembly, when X in ".-X" is
+ still unknown. Since we don't have pc-relative relocations in a.out,
+ this is invalid. What to do if anything for a.out, is to add
+ pc-relative relocations everywhere including the elinux program
+ loader. For ELF, allow straight-forward PC-relative relocations,
+ which are always relative to the location after the relocation. */
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour
+ || (fixP->fx_r_type != BFD_RELOC_8_PCREL
+ && fixP->fx_r_type != BFD_RELOC_16_PCREL
+ && fixP->fx_r_type != BFD_RELOC_32_PCREL
+ && fixP->fx_r_type != BFD_RELOC_CRIS_LAPCQ_OFFSET))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("Invalid pc-relative relocation"));
+ return fixP->fx_size + addr;
+}
+
+/* We have no need to give defaults for symbol-values. */
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* If this function returns non-zero, it prevents the relocation
+ against symbol(s) in the FIXP from being replaced with relocations
+ against section symbols, and guarantees that a relocation will be
+ emitted even when the value can be resolved locally. */
+int
+md_cris_force_relocation (struct fix *fixp)
+{
+ switch (fixp->fx_r_type)
+ {
+ case BFD_RELOC_CRIS_16_GOT:
+ case BFD_RELOC_CRIS_32_GOT:
+ case BFD_RELOC_CRIS_16_GOTPLT:
+ case BFD_RELOC_CRIS_32_GOTPLT:
+ case BFD_RELOC_CRIS_32_GOTREL:
+ case BFD_RELOC_CRIS_32_PLT_GOTREL:
+ case BFD_RELOC_CRIS_32_PLT_PCREL:
+ return 1;
+ default:
+ ;
+ }
+
+ return generic_force_reloc (fixp);
+}
+
+/* Check and emit error if broken-word handling has failed to fix up a
+ case-table. This is called from write.c, after doing everything it
+ knows about how to handle broken words. */
+
+void
+tc_cris_check_adjusted_broken_word (offsetT new_offset, struct broken_word *brokwP)
+{
+ if (new_offset > 32767 || new_offset < -32768)
+ /* We really want a genuine error, not a warning, so make it one. */
+ as_bad_where (brokwP->frag->fr_file, brokwP->frag->fr_line,
+ _("Adjusted signed .word (%ld) overflows: `switch'-statement too large."),
+ (long) new_offset);
+}
+
+/* Make a leading REGISTER_PREFIX_CHAR mandatory for all registers. */
+
+static void
+cris_force_reg_prefix (void)
+{
+ demand_register_prefix = TRUE;
+}
+
+/* Do not demand a leading REGISTER_PREFIX_CHAR for all registers. */
+
+static void
+cris_relax_reg_prefix (void)
+{
+ demand_register_prefix = FALSE;
+}
+
+/* Adjust for having a leading '_' on all user symbols. */
+
+static void
+cris_sym_leading_underscore (void)
+{
+ /* 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)
+ 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 (void)
+{
+ if (symbols_have_leading_underscore)
+ 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 (int ignore ATTRIBUTE_UNUSED)
+{
+ static const struct syntaxes
+ {
+ const char *const operand;
+ void (*fn) (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 (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 (int dummy)
+{
+ if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+ as_bad (_("Pseudodirective .loc is only valid when generating ELF"));
+ else
+ dwarf2_directive_loc (dummy);
+}
+
+/* Worker for .dtpoffd: generate a R_CRIS_32_DTPREL reloc, as for
+ expr:DTPREL but for use in debug info. */
+
+static void
+s_cris_dtpoff (int bytes)
+{
+ expressionS ex;
+ char *p;
+
+ if (bytes != 4)
+ as_fatal (_("internal inconsistency problem: %s called for %d bytes"),
+ __FUNCTION__, bytes);
+
+ expression (&ex);
+
+ p = frag_more (bytes);
+ md_number_to_chars (p, 0, bytes);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE,
+ BFD_RELOC_CRIS_32_DTPREL);
+
+ demand_empty_rest_of_line ();
+}
+
+
+/* Translate a <arch> string (as common to --march=<arch> and .arch <arch>)
+ into an enum. If the string *STR is recognized, *STR is updated to point
+ to the end of the string. If the string is not recognized,
+ arch_cris_unknown is returned. */
+
+static enum cris_archs
+cris_arch_from_string (char **str)
+{
+ static const struct cris_arch_struct
+ {
+ const char *const name;
+ enum cris_archs arch;
+ } arch_table[] =
+ /* Keep in order longest-first for choices where one is a prefix
+ of another. */
+ {{"v0_v10", arch_cris_any_v0_v10},
+ {"v10", arch_crisv10},
+ {"v32", arch_crisv32},
+ {"common_v10_v32", arch_cris_common_v10_v32}};
+
+ const struct cris_arch_struct *ap;
+
+ for (ap = arch_table;
+ ap < arch_table + sizeof (arch_table) / sizeof (arch_table[0]);
+ ap++)
+ {
+ int len = strlen (ap->name);
+
+ if (strncmp (*str, ap->name, len) == 0
+ && (str[0][len] == 0 || ISSPACE (str[0][len])))
+ {
+ *str += strlen (ap->name);
+ return ap->arch;
+ }
+ }
+
+ return arch_cris_unknown;
+}
+
+/* Return nonzero if architecture version ARCH matches version range in
+ IVER. */
+
+static int
+cris_insn_ver_valid_for_arch (enum cris_insn_version_usage iver,
+ enum cris_archs arch)
+{
+ switch (arch)
+ {
+ case arch_cris_any_v0_v10:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_warning
+ || iver == cris_ver_v0_3
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10
+ || iver == cris_ver_v8
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v8_10
+ || iver == cris_ver_v10
+ || iver == cris_ver_v10p);
+
+ case arch_crisv32:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v10p
+ || iver == cris_ver_v32p);
+
+ case arch_cris_common_v10_v32:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v10p);
+
+ case arch_crisv0:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v0_3
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10);
+
+ case arch_crisv3:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v0_3
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10);
+
+ case arch_crisv8:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10
+ || iver == cris_ver_v8
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v8_10);
+
+ case arch_crisv10:
+ return
+ (iver == cris_ver_version_all
+ || iver == cris_ver_v3p
+ || iver == cris_ver_v0_10
+ || iver == cris_ver_sim_v0_10
+ || iver == cris_ver_v3_10
+ || iver == cris_ver_v8p
+ || iver == cris_ver_v8_10
+ || iver == cris_ver_v10
+ || iver == cris_ver_v10p);
+
+ default:
+ BAD_CASE (arch);
+ }
+}
+
+/* Assert that the .arch ARCHCHOICE1 is compatible with the specified or
+ default --march=<ARCHCHOICE2> option. */
+
+static void
+s_cris_arch (int dummy ATTRIBUTE_UNUSED)
+{
+ /* Right now we take the easy route and check for sameness. It's not
+ obvious that allowing e.g. --march=v32 and .arch common_v0_v32
+ would be more useful than confusing, implementation-wise and
+ user-wise. */
+
+ char *str = input_line_pointer;
+ enum cris_archs arch = cris_arch_from_string (&str);
+
+ if (arch == arch_cris_unknown)
+ {
+ as_bad (_("unknown operand to .arch"));
+
+ /* For this one, str does not reflect the end of the operand,
+ since there was no matching arch. Skip it manually; skip
+ things that can be part of a word (a name). */
+ while (is_part_of_name (*str))
+ str++;
+ }
+ else if (arch != cris_arch)
+ as_bad (_(".arch <arch> requires a matching --march=... option"));
+
+ input_line_pointer = str;
+ demand_empty_rest_of_line ();
+ return;
+}
+
+/*
+ * Local variables:
+ * eval: (c-set-style "gnu")
+ * indent-tabs-mode: t
+ * End:
+ */