/* tc-cris.c -- Assembler code for the CRIS CPU core.
- Copyright 2000, 2001 Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
Contributed by Axis Communications AB, Lund, Sweden.
Originally written for GAS 1.38.1 by Mikael Asker.
MA 02111-1307, USA. */
#include <stdio.h>
-#include <ctype.h>
#include "as.h"
+#include "safe-ctype.h"
#include "subsegs.h"
#include "opcode/cris.h"
#include "dwarf2dbg.h"
#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 PIC_SUFFIX_CHAR ':'
static void cris_relax_reg_prefix PARAMS ((void));
static void cris_sym_leading_underscore PARAMS ((void));
static void cris_sym_no_leading_underscore PARAMS ((void));
+static char *cris_insn_first_word_frag PARAMS ((void));
/* Handle to the opcode hash table. */
static struct hash_control *op_hash = NULL;
}
}
+/* 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 (seg, fragP, stretch)
+ 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_CONDITIONAL_BRANCH, 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;
+
+ 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
{
case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
- {
- /* The symbol lies in the same segment - a relaxable case. */
- fragP->fr_subtype
- = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
- }
+ /* The symbol lies in the same segment - a relaxable case. */
+ fragP->fr_subtype
+ = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
else
- {
- /* Unknown or not the same segment, so not relaxable. */
- char *writep;
-
- /* A small branch-always (2 bytes) to the "real" branch
- instruction, plus a delay-slot nop (2 bytes), plus a
- jump (2 plus 4 bytes). See gen_cond_branch_32. */
- fragP->fr_fix += 2 + 2 + 2 + 4;
- writep = fragP->fr_literal + old_fr_fix;
- gen_cond_branch_32 (fragP->fr_opcode, writep, fragP,
- fragP->fr_symbol, (symbolS *) NULL,
- fragP->fr_offset);
- frag_wane (fragP);
- }
- break;
-
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
- case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
- /* We *might* give a better initial guess if we peek at offsets
- now, but the caller will relax correctly and without this, so
- don't bother. */
+ /* Unknown or not the same segment, so not relaxable. */
+ fragP->fr_subtype
+ = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, 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):
/* Go for dword if not absolute or same segment. */
fragP->fr_subtype
= ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD);
- fragP->fr_var += 4;
+ 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
{
}
break;
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
+ case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, 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;
+
default:
BAD_CASE (fragP->fr_subtype);
}
opcodep = fragP->fr_opcode;
symbolP = fragP->fr_symbol;
- target_address
- = (symbolP
- ? S_GET_VALUE (symbolP) + symbol_get_frag(fragP->fr_symbol)->fr_address
- : 0 ) + fragP->fr_offset;
+ 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)
break;
case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
- var_partp[0] = target_address - (address_of_var_part + 1);
+ if (symbolP == NULL)
+ as_fatal (_("internal inconsistency in %s: bdapq no symbol"),
+ __FUNCTION__);
+ opcodep[0] = S_GET_VALUE (symbolP);
var_part_size = 0;
break;
opcodep[0] = BDAP_PC_LOW + (1 << 4);
opcodep[1] &= 0xF0;
opcodep[1] |= BDAP_INCR_HIGH;
- md_number_to_chars (var_partp, (long) (target_address), 2);
+ 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;
}
}
+/* 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 ()
+{
+ 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
struct cris_prefix prefix;
char *opcodep;
char *p;
- int insn_size = 0;
know (str);
case PREFIX_BDAP:
case PREFIX_BIAP:
case PREFIX_DIP:
- insn_size += 2;
- opcodep = frag_more (2);
+ opcodep = cris_insn_first_word_frag ();
/* Output the prefix opcode. */
md_number_to_chars (opcodep, (long) prefix.opcode, 2);
= (prefix.kind == PREFIX_DIP
? 4 : cris_get_pic_reloc_size (prefix.reloc));
- insn_size += relocsize;
p = frag_more (relocsize);
fix_new_exp (frag_now, (p - frag_now->fr_literal), relocsize,
&prefix.expr, 0, prefix.reloc);
break;
case PREFIX_PUSH:
- insn_size += 2;
- opcodep = frag_more (2);
+ opcodep = cris_insn_first_word_frag ();
/* Output the prefix opcode. Being a "push", we add the negative
size of the register to "sp". */
return;
/* Done with the prefix. Continue with the main instruction. */
- insn_size += 2;
- opcodep = frag_more (2);
+ 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);
is_undefined = 1;
}
- if (output_instruction.expr.X_op == O_constant
- || to_seg == now_seg || is_undefined)
+ if (to_seg == now_seg || is_undefined)
{
/* Handle complex expressions. */
valueT addvalue
- = (output_instruction.expr.X_op_symbol != NULL
- ? 0 : output_instruction.expr.X_add_number);
+ = (SIMPLE_EXPR (&output_instruction.expr)
+ ? output_instruction.expr.X_add_number
+ : 0);
symbolS *sym
- = (output_instruction.expr.X_op_symbol != NULL
- ? make_expr_symbol (&output_instruction.expr)
- : output_instruction.expr.X_add_symbol);
+ = (SIMPLE_EXPR (&output_instruction.expr)
+ ? output_instruction.expr.X_add_symbol
+ : make_expr_symbol (&output_instruction.expr));
/* If is_undefined, then the expression may BECOME now_seg. */
length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
{
/* We have: to_seg != now_seg && to_seg != undefined_section.
This means it is a branch to a known symbol in another
- section. Code in data? Weird but valid. Emit a 32-bit
- branch. */
+ section, perhaps an absolute address. Emit a 32-bit branch. */
char *cond_jump = frag_more (10);
- insn_size += 10;
gen_cond_branch_32 (opcodep, cond_jump, frag_now,
output_instruction.expr.X_add_symbol,
(symbolS *) NULL,
BAD_CASE (output_instruction.imm_oprnd_size);
}
- insn_size += output_instruction.imm_oprnd_size;
p = frag_more (output_instruction.imm_oprnd_size);
fix_new_exp (frag_now, (p - frag_now->fr_literal),
output_instruction.imm_oprnd_size,
output_instruction.reloc);
}
}
-
- if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
- dwarf2_emit_insn (insn_size);
}
/* Low level text-to-bits assembly. */
/* 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)
+ for (operands = insn_text; ISLOWER (*operands); ++operands)
;
/* Terminate the opcode after letters, but save the character there if
(*cPP)++;
if ((**cPP == 'C' || **cPP == 'c')
- && ! isalnum ((*cPP)[1]))
+ && ! ISALNUM ((*cPP)[1]))
{
/* It's "PC": consume the "c" and we're done. */
(*cPP)++;
/* Hopefully r[0-9] or r1[0-5]. Consume 'R' or 'r'. */
(*cPP)++;
- if (isdigit (**cPP))
+ if (ISDIGIT (**cPP))
{
/* It's r[0-9]. Consume and check the next digit. */
*regnop = **cPP - '0';
(*cPP)++;
- if (! isalnum (**cPP))
+ if (! ISALNUM (**cPP))
{
/* No more digits, we're done. */
return 1;
s1 = name_begin;
s2 = sregp->name;
- while (*s2 != '\0'
- && (isupper (*s1) ? tolower (*s1) == *s2 : *s1 == *s2))
+ 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))
+ if (*s2 == 0 && ! ISALNUM (*s1))
{
/* We have a match. Update the pointer and be done. */
*cPP = s1;
whitespace. Anything else, and we consider it a failure. */
if (**cPP != ','
&& **cPP != 0
- && ! isspace (**cPP))
+ && ! ISSPACE (**cPP))
return 0;
else
return 1;
/* Put out the prefix opcode; assume quick immediate mode at first. */
opcode = BDAP_QUICK_OPCODE | (base_regno << 12);
- opcodep = frag_more (2);
+ opcodep = cris_insn_first_word_frag ();
md_number_to_chars (opcodep, opcode, 2);
if (exprP->X_op == O_constant)
{
/* Handle complex expressions. */
valueT addvalue
- = exprP->X_op_symbol != NULL ? 0 : exprP->X_add_number;
+ = SIMPLE_EXPR (exprP) ? exprP->X_add_number : 0;
symbolS *sym
- = (exprP->X_op_symbol != NULL
- ? make_expr_symbol (exprP) : exprP->X_add_symbol);
+ = (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. */
break;
/* Allow complex expressions as the constant part. It still
- has to be a assembly-time constant or there will be an
+ has to be an assembly-time constant or there will be an
error emitting the reloc. This makes the PIC qualifiers
- idempotent; foo:GOT+32 == foo+32:GOT. The former we
+ 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);
relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
if (fixP->fx_pcrel)
- /* FIXME: Is this correct? */
- relP->addend = fixP->fx_addnumber;
+ relP->addend = 0;
else
- /* At least *this one* is correct. */
relP->addend = fixP->fx_offset;
/* This is the standard place for KLUDGEs to work around bugs in
/* 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. */
-int
+void
md_apply_fix3 (fixP, valP, seg)
fixS *fixP;
valueT *valP;
segT seg;
{
- long val = *valP;
-
+ /* 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)
}
else
{
- /* I took this from tc-arc.c, since we used to not support
- fx_subsy != NULL. I'm not totally sure it's TRT. */
+ /* We can't actually support subtracting a symbol. */
if (fixP->fx_subsy != (symbolS *) NULL)
- {
- if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
- val -= S_GET_VALUE (fixP->fx_subsy);
- else
- {
- /* We can't actually support subtracting a symbol. */
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("expression too complex"));
- }
- }
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("expression too complex"));
cris_number_to_imm (buf, val, fixP->fx_size, fixP, seg);
}
-
- return 1;
}
/* All relocations are relative to the location just after the fixup;
return 0;
}
-/* Definition of TC_FORCE_RELOCATION.
- FIXME: Unsure of this. Can we omit it? Just copied from tc-i386.c
- when doing multi-object format with ELF, since it's the only other
- multi-object-format target with a.out and ELF. */
+/* 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 (fixp)
struct fix *fixp;
;
}
- return 0;
+ return S_FORCE_RELOC (fixp->fx_addsy);
}
/* Check and emit error if broken-word handling has failed to fix up a
the bfd is already created. */
if (symbols_have_leading_underscore == false)
- as_bad (".syntax %s requires command-line option `--underscore'",
+ as_bad (_(".syntax %s requires command-line option `--underscore'"),
SYNTAX_USER_SYM_LEADING_UNDERSCORE);
}
static void cris_sym_no_leading_underscore ()
{
if (symbols_have_leading_underscore == true)
- as_bad (".syntax %s requires command-line option `--no-underscore'",
+ as_bad (_(".syntax %s requires command-line option `--no-underscore'"),
SYNTAX_USER_SYM_NO_LEADING_UNDERSCORE);
}
int dummy;
{
if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
- as_bad ("Pseudodirective .file is only valid when generating ELF");
+ as_bad (_("Pseudodirective .file is only valid when generating ELF"));
else
dwarf2_directive_file (dummy);
}
int dummy;
{
if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
- as_bad ("Pseudodirective .loc is only valid when generating ELF");
+ as_bad (_("Pseudodirective .loc is only valid when generating ELF"));
else
dwarf2_directive_loc (dummy);
}