diff options
Diffstat (limited to 'binutils-2.25/gas/config/tc-cris.c')
-rw-r--r-- | binutils-2.25/gas/config/tc-cris.c | 4407 |
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, ®no)) + 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, ®no)) + 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, ®no)) + break; + else + { + out_insnp->opcode |= regno << 12; + continue; + } + + case 'r': + /* General register in bits <3:0>. */ + if (! get_gen_reg (&s, ®no)) + 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, + ®no, + &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, ®no) + || ! 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, ®no, + &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, ®no)) + { + 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, ®_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: + */ |