Fix Bug savannah/1825:
* config/tc-m68hc11.h (md_relax_frag): Define to support relaxations that are not pc-relative. (m68hc11_relax_frag): Declare. * config/tc-m68hc11.c (build_indexed_byte): Use a frag_var to handle the offsetable indexed addressing modes (n,r). (build_insn): Cleanup some locals. (m68hc11_relax_frag): New function imported from tc-cris.c to handle relaxation of difference between two symbols of same section. (md_convert_frag): For INDEXED_OFFSET relaxs, use the displacement only when this is a PC-relative operand and the offset is not absolute. (md_estimate_size_before_relax): Convert the INDEXED_OFFSET,UNDEF frag to INDEXED_OFFSET,STATE_BITS5 when the symbol is absolute; this will be handled by m68hc11_relax_frag.
This commit is contained in:
parent
2f9046641f
commit
c9e03e8be9
3 changed files with 163 additions and 26 deletions
|
@ -1,3 +1,21 @@
|
|||
2002-12-01 Stephane Carrez <stcarrez@nerim.fr>
|
||||
|
||||
Fix Bug savannah/1825:
|
||||
* config/tc-m68hc11.h (md_relax_frag): Define to support relaxations
|
||||
that are not pc-relative.
|
||||
(m68hc11_relax_frag): Declare.
|
||||
|
||||
* config/tc-m68hc11.c (build_indexed_byte): Use a frag_var to handle
|
||||
the offsetable indexed addressing modes (n,r).
|
||||
(build_insn): Cleanup some locals.
|
||||
(m68hc11_relax_frag): New function imported from tc-cris.c to handle
|
||||
relaxation of difference between two symbols of same section.
|
||||
(md_convert_frag): For INDEXED_OFFSET relaxs, use the displacement
|
||||
only when this is a PC-relative operand and the offset is not absolute.
|
||||
(md_estimate_size_before_relax): Convert the INDEXED_OFFSET,UNDEF frag
|
||||
to INDEXED_OFFSET,STATE_BITS5 when the symbol is absolute; this will
|
||||
be handled by m68hc11_relax_frag.
|
||||
|
||||
2002-12-01 Stephane Carrez <stcarrez@nerim.fr>
|
||||
|
||||
* config/tc-m68hc11.c (elf_flags): Set default ABI to gcc default
|
||||
|
|
|
@ -1933,14 +1933,21 @@ build_indexed_byte (op, format, move_insn)
|
|||
}
|
||||
else if (op->reg1 != REG_PC)
|
||||
{
|
||||
byte = (byte << 3) | 0xe2;
|
||||
symbolS *sym;
|
||||
offsetT off;
|
||||
|
||||
f = frag_more (1);
|
||||
number_to_chars_bigendian (f, byte, 1);
|
||||
|
||||
f = frag_more (2);
|
||||
fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
|
||||
&op->exp, FALSE, BFD_RELOC_16);
|
||||
number_to_chars_bigendian (f, 0, 2);
|
||||
sym = op->exp.X_add_symbol;
|
||||
off = op->exp.X_add_number;
|
||||
if (op->exp.X_op != O_symbol)
|
||||
{
|
||||
sym = make_expr_symbol (&op->exp);
|
||||
off = 0;
|
||||
}
|
||||
frag_var (rs_machine_dependent, 2, 2,
|
||||
ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_UNDF),
|
||||
sym, off, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2060,17 +2067,12 @@ build_insn (opcode, operands, nb_operands)
|
|||
char *f;
|
||||
long format;
|
||||
int move_insn = 0;
|
||||
fragS *frag;
|
||||
int where;
|
||||
|
||||
/* Put the page code instruction if there is one. */
|
||||
format = opcode->format;
|
||||
|
||||
frag = frag_now;
|
||||
where = frag_now_fix ();
|
||||
|
||||
if (format & M6811_OP_BRANCH)
|
||||
fix_new (frag, where, 1,
|
||||
fix_new (frag_now, frag_now_fix (), 1,
|
||||
&abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
|
||||
|
||||
if (format & OP_EXTENDED)
|
||||
|
@ -2732,6 +2734,97 @@ tc_gen_reloc (section, fixp)
|
|||
return reloc;
|
||||
}
|
||||
|
||||
/* 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:
|
||||
ldab sym2-(sym1-2),pc
|
||||
sym1:
|
||||
The offset can be 5, 9 or 16 bits long. */
|
||||
|
||||
long
|
||||
m68hc11_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 STATE_BITS16 case may geet here
|
||||
because of the different reasons that it's not relaxable. */
|
||||
switch (fragP->fr_subtype)
|
||||
{
|
||||
case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16):
|
||||
/* When we get to this state, the frag won't grow any more. */
|
||||
return 0;
|
||||
|
||||
case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5):
|
||||
case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9):
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
md_convert_frag (abfd, sec, fragP)
|
||||
bfd *abfd ATTRIBUTE_UNUSED;
|
||||
|
@ -2799,25 +2892,32 @@ md_convert_frag (abfd, sec, fragP)
|
|||
break;
|
||||
|
||||
case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5):
|
||||
if (fragP->fr_opcode[0] == 3
|
||||
&& fragP->fr_symbol != 0
|
||||
&& S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
|
||||
value = disp;
|
||||
fragP->fr_opcode[0] = fragP->fr_opcode[0] << 6;
|
||||
if ((fragP->fr_opcode[0] & 0x0ff) == 0x0c0)
|
||||
fragP->fr_opcode[0] |= disp & 0x1f;
|
||||
else
|
||||
fragP->fr_opcode[0] |= value & 0x1f;
|
||||
fragP->fr_opcode[0] |= value & 0x1f;
|
||||
break;
|
||||
|
||||
case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9):
|
||||
if (fragP->fr_opcode[0] == 3
|
||||
&& fragP->fr_symbol != 0
|
||||
&& S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
|
||||
value = disp;
|
||||
fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3);
|
||||
fragP->fr_opcode[0] |= 0xE0;
|
||||
fix_new (fragP, fragP->fr_fix, 1,
|
||||
fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_8);
|
||||
fragP->fr_opcode[0] |= (value >> 8) & 1;
|
||||
fragP->fr_opcode[1] = value;
|
||||
fragP->fr_fix += 1;
|
||||
break;
|
||||
|
||||
case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16):
|
||||
fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3);
|
||||
fragP->fr_opcode[0] |= 0xe2;
|
||||
if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa)
|
||||
if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa
|
||||
&& fragP->fr_symbol != 0
|
||||
&& S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
|
||||
{
|
||||
fixp = fix_new (fragP, fragP->fr_fix, 2,
|
||||
fragP->fr_symbol, fragP->fr_offset,
|
||||
|
@ -2927,13 +3027,23 @@ md_estimate_size_before_relax (fragP, segment)
|
|||
case STATE_INDEXED_OFFSET:
|
||||
assert (current_architecture & cpu6812);
|
||||
|
||||
/* Switch the indexed operation to 16-bit mode. */
|
||||
fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
|
||||
fragP->fr_opcode[0] |= 0xe2;
|
||||
fragP->fr_fix++;
|
||||
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
|
||||
fragP->fr_offset, 0, BFD_RELOC_16);
|
||||
fragP->fr_fix++;
|
||||
if (fragP->fr_symbol
|
||||
&& S_GET_SEGMENT (fragP->fr_symbol) == absolute_section)
|
||||
{
|
||||
fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_OFFSET,
|
||||
STATE_BITS5);
|
||||
/* Return the size of the variable part of the frag. */
|
||||
return md_relax_table[fragP->fr_subtype].rlx_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Switch the indexed operation to 16-bit mode. */
|
||||
fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
|
||||
fragP->fr_opcode[0] |= 0xe2;
|
||||
fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
|
||||
fragP->fr_offset, 0, BFD_RELOC_16);
|
||||
fragP->fr_fix += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_XBCC_BRANCH:
|
||||
|
|
|
@ -93,6 +93,15 @@ extern int m68hc11_parse_long_option PARAMS ((char *));
|
|||
#define TC_GENERIC_RELAX_TABLE md_relax_table
|
||||
extern struct relax_type md_relax_table[];
|
||||
|
||||
/* 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) \
|
||||
: m68hc11_relax_frag (SEG, FRAGP, STRETCH))
|
||||
extern long m68hc11_relax_frag PARAMS ((segT, fragS*, long));
|
||||
|
||||
#define TC_HANDLES_FX_DONE
|
||||
|
||||
#define DIFF_EXPR_OK /* .-foo gets turned into PC relative relocs */
|
||||
|
|
Loading…
Reference in a new issue