aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog17
-rw-r--r--gas/config/tc-cris.c137
-rw-r--r--gas/config/tc-cris.h10
3 files changed, 154 insertions, 10 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 6159ef2..3ad2f4f 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,20 @@
+2002-10-23 Hans-Peter Nilsson <hp@axis.com>
+
+ * config/tc-cris.c (SIMPLE_EXPR): New macro.
+ (cris_relax_frag): New function.
+ (md_estimate_size_before_relax) <case ENCODE_RELAX
+ (STATE_BASE_PLUS_DISP_PREFIX, STATE_UNDF)>: Pass on unresolved
+ expressions that will become absolute expressions to relaxation.
+ (md_convert_frag) <case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX,
+ STATE_WORD)>: Expect only absolute expressions. Use the symbol
+ value, not distance to symbol.
+ <case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE)>:
+ Ditto. Correct placement of fixup.
+ (md_assemble): Use SIMPLE_EXPR when dissecting expressions.
+ (gen_bdap): Ditto.
+ * config/tc-cris.h (cris_relax_frag): Declare.
+ (md_relax_frag): Define.
+
2002-10-22 Alan Modra <amodra@bigpond.net.au>
* config/obj-elf.c (special_sections): Use correct types for init
diff --git a/gas/config/tc-cris.c b/gas/config/tc-cris.c
index e41b467..b263da7 100644
--- a/gas/config/tc-cris.c
+++ b/gas/config/tc-cris.c
@@ -43,6 +43,13 @@
#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 ':'
@@ -330,6 +337,98 @@ cris_target_format ()
}
}
+/* 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 geet 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
@@ -386,6 +485,17 @@ md_estimate_size_before_relax (fragP, segment_type)
= 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. */
@@ -526,7 +636,10 @@ md_convert_frag (abfd, sec, fragP)
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;
@@ -536,7 +649,10 @@ md_convert_frag (abfd, sec, fragP)
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;
@@ -813,12 +929,13 @@ md_assemble (str)
{
/* 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;
@@ -2386,10 +2503,10 @@ gen_bdap (base_regno, exprP)
{
/* 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. */
diff --git a/gas/config/tc-cris.h b/gas/config/tc-cris.h
index d20e0a8..b07f6de 100644
--- a/gas/config/tc-cris.h
+++ b/gas/config/tc-cris.h
@@ -75,6 +75,16 @@ extern const int md_long_jump_size;
extern const struct relax_type md_cris_relax_table[];
#define TC_GENERIC_RELAX_TABLE md_cris_relax_table
+long cris_relax_frag PARAMS ((segT, fragS *, long));
+
+/* GAS only handles relaxations for pc-relative data targeting addresses
+ in the same segment, so we have to handle the rest on our own. */
+#define md_relax_frag(SEG, FRAGP, STRETCH) \
+ ((FRAGP)->fr_symbol != NULL \
+ && S_GET_SEGMENT ((FRAGP)->fr_symbol) == (SEG) \
+ ? relax_frag (SEG, FRAGP, STRETCH) \
+ : cris_relax_frag (SEG, FRAGP, STRETCH))
+
#define TC_FORCE_RELOCATION(FIX) md_cris_force_relocation (FIX)
extern int md_cris_force_relocation PARAMS ((struct fix *));