* 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.
This commit is contained in:
Hans-Peter Nilsson 2002-10-22 23:45:40 +00:00
parent c84e511732
commit 1c97116001
3 changed files with 154 additions and 10 deletions

View File

@ -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

View File

@ -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. */

View File

@ -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 *));