/* tc-cris.c -- Assembler code for the CRIS CPU core.
- Copyright 2000, 2001, 2002, 2003, 2004, 2006, 2007
- Free Software Foundation, Inc.
+ Copyright (C) 2000-2020 Free Software Foundation, Inc.
Contributed by Axis Communications AB, Lund, Sweden.
Originally written for GAS 1.38.1 by Mikael Asker.
expressionS expr;
/* If there's an expression, we might need a relocation. Here's the
- type of what relocation to start relaxaton with.
+ type of what relocation to start relaxation 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;
arch_cris_any_v0_v10, arch_crisv32, arch_cris_common_v10_v32
};
-static enum cris_archs cris_arch_from_string (char **);
+static enum cris_archs cris_arch_from_string (const char **);
static int cris_insn_ver_valid_for_arch (enum cris_insn_version_usage,
enum cris_archs);
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 cris_create_short_jump (char *, addressT, addressT, fragS *,
- symbolS *);
static void s_syntax (int);
static void s_cris_file (int);
static void s_cris_loc (int);
static char *cris_insn_first_word_frag (void);
/* Handle to the opcode hash table. */
-static struct hash_control *op_hash = NULL;
+static htab_t 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
/* Used to check integrity of the relaxation.
One of 2 = long, 1 = word, or 0 = byte. */
- int length_code;
+ int length_code ATTRIBUTE_UNUSED;
/* Size in bytes of variable-sized part of frag. */
int var_part_size = 0;
}
/* Generate a short jump around a secondary jump table.
- Used by md_create_long_jump.
+ Also called from md_create_long_jump, when sufficient. */
- This used to be md_create_short_jump, but is now called from
- md_create_long_jump instead, when sufficient, since the sizes of the
- jumps are the same for pre-v32. */
-
-static void
-cris_create_short_jump (char *storep, addressT from_addr, addressT to_addr,
+void
+md_create_short_jump (char *storep, addressT from_addr, addressT to_addr,
fragS *fragP ATTRIBUTE_UNUSED,
symbolS *to_symbol ATTRIBUTE_UNUSED)
{
/* 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;
}
a nop to keep disassembly sane. */
md_number_to_chars (storep + 4, nop_opcode, 2);
}
- else
+ 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);
/* 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.
long int max_short_plus_distance
= cris_arch != arch_crisv32 ? BRANCH_WF + 3 : BRANCH_WF_V32 + 3;
- /* 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.) */
- if (cris_arch == arch_cris_common_v10_v32)
- as_fatal (_("Out-of-range .word offset handling\
- is not implemented for .arch common_v10_v32"));
-
distance = to_addr - from_addr;
if (max_short_minus_distance <= distance
&& distance <= max_short_plus_distance)
- /* Then make it a "short" long jump. */
- cris_create_short_jump (storep, from_addr, to_addr, fragP,
+ {
+ /* Then make it a "short" long jump. */
+ md_create_short_jump (storep, from_addr, to_addr, fragP,
to_symbol);
+ if (cris_arch == arch_crisv32)
+ md_number_to_chars (storep + 6, NOP_OPCODE_V32, 2);
+ else
+ md_number_to_chars (storep + 6, NOP_OPCODE, 2);
+ }
else
{
/* We have a "long" long jump: "JUMP [PC+]". If CRISv32, always
void
md_begin (void)
{
- const char *hashret = NULL;
int i = 0;
/* Set up a hash table for the instructions. */
- op_hash = hash_new ();
+ op_hash = str_htab_create ();
if (op_hash == NULL)
as_fatal (_("Virtual memory exhausted"));
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);
+ /* Need to cast to get rid of "const". FIXME: Fix str_hash_insert instead. */
+ str_hash_insert (op_hash, name, (void *) &cris_opcodes[i]);
do
{
if (cris_opcodes[i].match & cris_opcodes[i].lose)
}
}
+/* Helper error-reporting function: calls as_bad for a format string
+ for a single value and zeroes the offending value (zero assumed
+ being a valid value) to avoid repeated error reports in later value
+ checking. */
+
+static void
+cris_bad (const char *format, offsetT *valp)
+{
+ /* We cast to long so the format string can assume that format. */
+ as_bad (format, (long) *valp);
+ *valp = 0;
+}
+
/* Low level text-to-bits assembly. */
static void
}
/* Find the instruction. */
- instruction = (struct cris_opcode *) hash_find (op_hash, insn_text);
+ instruction = (struct cris_opcode *) str_hash_find (op_hash, insn_text);
if (instruction == NULL)
{
as_bad (_("Unknown opcode: `%s'"), insn_text);
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);
+ cris_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;
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);
+ cris_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;
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);
+ cris_bad (_("Immediate value not in 6 bit range: %ld"),
+ &out_insnp->expr.X_add_number);
+
out_insnp->reloc = BFD_RELOC_CRIS_SIGNED_6;
continue;
}
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);
+ cris_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;
}
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))
pseudo yet, so some of this is just unused
framework. */
if (out_insnp->spec_reg->warning)
- as_warn (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. */
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);
+ cris_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
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);
+ cris_bad (_("Immediate value not in 16 bit range: %ld"),
+ &out_insnp->expr.X_add_number);
out_insnp->imm_oprnd_size = 2;
break;
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);
+ cris_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);
+ cris_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);
+ cris_bad (_("Immediate value not in 8 bit unsigned range: %ld"),
+ &out_insnp->expr.X_add_number);
}
/* Fall through. */
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);
+ cris_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);
+ cris_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);
+ cris_bad (_("Immediate value not in 16 bit unsigned range: %ld"),
+ &out_insnp->expr.X_add_number);
}
out_insnp->imm_oprnd_size = 2;
break;
cris_get_expression (char **cPP, expressionS *exprP)
{
char *saved_input_line_pointer;
- segT exp;
/* The "expression" function expects to find an expression at the
global variable input_line_pointer, so we have to save it to give
return 0;
}
- exp = expression (exprP);
+ expression (exprP);
if (exprP->X_op == O_illegal || exprP->X_op == O_absent)
{
input_line_pointer = saved_input_line_pointer;
code as assembly code, but if they do, they should be able enough to
find out the correct bit patterns and use them. */
-char *
+const char *
md_atof (int type ATTRIBUTE_UNUSED, char *litp ATTRIBUTE_UNUSED,
int *sizep ATTRIBUTE_UNUSED)
{
GAS does not understand. */
int
-md_parse_option (int arg, char *argp ATTRIBUTE_UNUSED)
+md_parse_option (int arg, const char *argp ATTRIBUTE_UNUSED)
{
switch (arg)
{
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;
case OPTION_ARCH:
{
- char *str = argp;
+ const char *str = argp;
enum cris_archs argarch = cris_arch_from_string (&str);
if (argarch == arch_cris_unknown)
return 0;
}
- relP = (arelent *) xmalloc (sizeof (arelent));
- assert (relP != 0);
- relP->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ relP = XNEW (arelent);
+ gas_assert (relP != 0);
+ relP->sym_ptr_ptr = XNEW (asymbol *);
*relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
_(" --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"));
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"));
+ /* 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);
- }
+ /* 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;
arch_cris_unknown is returned. */
static enum cris_archs
-cris_arch_from_string (char **str)
+cris_arch_from_string (const char **str)
{
static const struct cris_arch_struct
{
|| iver == cris_ver_v8_10
|| iver == cris_ver_v10
|| iver == cris_ver_v10p);
-
+
case arch_crisv32:
return
(iver == cris_ver_version_all
would be more useful than confusing, implementation-wise and
user-wise. */
- char *str = input_line_pointer;
+ const char *str = input_line_pointer;
enum cris_archs arch = cris_arch_from_string (&str);
if (arch == arch_cris_unknown)
else if (arch != cris_arch)
as_bad (_(".arch <arch> requires a matching --march=... option"));
- input_line_pointer = str;
+ input_line_pointer = (char *) str;
demand_empty_rest_of_line ();
return;
}