* config/tc-mips.c (prev_insn_reloc_type): New static variable.

(RELAX_MIPS16_ENCODE): Add dslot and jal_dslot arguments, and
	store them.  Adjust other RELAX_MIPS16 macros.
	(RELAX_MIPS16_DSLOT): Define.
	(RELAX_MIPS16_JAL_DSLOT): Define.
	(append_insn): Pass new arguments to RELAX_MIPS16_ENCODE.  Correct
	handling of whether previous instruction has a fixup.  Set
	prev_insn_reloc_type.
	(mips_no_prev_insn): Clear prev_insn_reloc_type.
	(mips16_extended_frag): Use the right base address for a PC
	relative add or load.
	(md_convert_frag): Likewise.  If a PC relative add or load is
	used, record the alignment for the section.
This commit is contained in:
Ian Lance Taylor 1996-12-15 03:42:36 +00:00
parent 39e5bea281
commit a677feeba4
2 changed files with 100 additions and 26 deletions

View File

@ -1,3 +1,19 @@
Sat Dec 14 22:37:27 1996 Ian Lance Taylor <ian@cygnus.com>
* config/tc-mips.c (prev_insn_reloc_type): New static variable.
(RELAX_MIPS16_ENCODE): Add dslot and jal_dslot arguments, and
store them. Adjust other RELAX_MIPS16 macros.
(RELAX_MIPS16_DSLOT): Define.
(RELAX_MIPS16_JAL_DSLOT): Define.
(append_insn): Pass new arguments to RELAX_MIPS16_ENCODE. Correct
handling of whether previous instruction has a fixup. Set
prev_insn_reloc_type.
(mips_no_prev_insn): Clear prev_insn_reloc_type.
(mips16_extended_frag): Use the right base address for a PC
relative add or load.
(md_convert_frag): Likewise. If a PC relative add or load is
used, record the alignment for the section.
Fri Dec 13 13:00:33 1996 Ian Lance Taylor <ian@cygnus.com>
* write.c (adjust_reloc_syms): Don't reduce a reloc against a

View File

@ -304,6 +304,9 @@ static struct frag *prev_insn_frag;
/* The offset into prev_insn_frag for the previous instruction. */
static long prev_insn_where;
/* The reloc type for the previous instruction, if any. */
static bfd_reloc_code_real_type prev_insn_reloc_type;
/* The reloc for the previous instruction, if any. */
static fixS *prev_insn_fixp;
@ -452,30 +455,34 @@ static const int mips16_to_32_reg_map[] =
the same time that we support the relaxation described above. We
use the high bit of the subtype field to distinguish these cases.
The information we store for this type of relaxation is simply the
argument code found in the opcode file for this relocation, and
whether the user explicitly requested a small or extended form.
That tells us the size of the value, and how it should be stored.
We also store whether the fragment is considered to be extended or
not. We also store whether this is known to be a branch to a
different section, whether we have tried to relax this frag yet,
and whether we have ever extended a PC relative fragment because of
a shift count. */
#define RELAX_MIPS16_ENCODE(type, small, ext) \
(0x80000000 \
| ((type) & 0xff) \
| ((small) ? 0x100 : 0) \
| ((ext) ? 0x200 : 0))
The information we store for this type of relaxation is the
argument code found in the opcode file for this relocation, whether
the user explicitly requested a small or extended form, and whether
the relocation is in a jump or jal delay slot. That tells us the
size of the value, and how it should be stored. We also store
whether the fragment is considered to be extended or not. We also
store whether this is known to be a branch to a different section,
whether we have tried to relax this frag yet, and whether we have
ever extended a PC relative fragment because of a shift count. */
#define RELAX_MIPS16_ENCODE(type, small, ext, dslot, jal_dslot) \
(0x80000000 \
| ((type) & 0xff) \
| ((small) ? 0x100 : 0) \
| ((ext) ? 0x200 : 0) \
| ((dslot) ? 0x400 : 0) \
| ((jal_dslot) ? 0x800 : 0))
#define RELAX_MIPS16_P(i) (((i) & 0x80000000) != 0)
#define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x400) != 0)
#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x400)
#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x400)
#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x800) != 0)
#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x800)
#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x800)
#define RELAX_MIPS16_DSLOT(i) (((i) & 0x400) != 0)
#define RELAX_MIPS16_JAL_DSLOT(i) (((i) & 0x800) != 0)
#define RELAX_MIPS16_EXTENDED(i) (((i) & 0x1000) != 0)
#define RELAX_MIPS16_MARK_EXTENDED(i) ((i) | 0x1000)
#define RELAX_MIPS16_CLEAR_EXTENDED(i) ((i) &~ 0x1000)
#define RELAX_MIPS16_LONG_BRANCH(i) (((i) & 0x2000) != 0)
#define RELAX_MIPS16_MARK_LONG_BRANCH(i) ((i) | 0x2000)
#define RELAX_MIPS16_CLEAR_LONG_BRANCH(i) ((i) &~ 0x2000)
/* Prototypes for static functions. */
@ -1384,7 +1391,11 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
assert (mips16 && address_expr != NULL);
f = frag_var (rs_machine_dependent, 4, 0,
RELAX_MIPS16_ENCODE (reloc_type - BFD_RELOC_UNUSED,
mips16_small, mips16_ext),
mips16_small, mips16_ext,
(prev_pinfo
& INSN_UNCOND_BRANCH_DELAY),
(prev_insn_reloc_type
== BFD_RELOC_MIPS16_JMP)),
make_expr_symbol (address_expr), (long) 0,
(char *) NULL);
}
@ -1821,6 +1832,10 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
prev_prev_insn.insn_mo = &dummy_opcode;
prev_insn.insn_mo = &dummy_opcode;
}
prev_insn_fixp = NULL;
prev_insn_reloc_type = BFD_RELOC_UNUSED;
prev_insn_extended = 0;
}
else if (pinfo & INSN_COND_BRANCH_LIKELY)
{
@ -1832,6 +1847,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
/* Update the previous insn information. */
prev_prev_insn = *ip;
prev_insn.insn_mo = &dummy_opcode;
prev_insn_fixp = NULL;
prev_insn_reloc_type = BFD_RELOC_UNUSED;
prev_insn_extended = 0;
}
else
{
@ -1846,17 +1864,28 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
immediately; since this insn is not a branch, we know it
is not in a delay slot. */
prev_insn_is_delay_slot = 0;
prev_insn_fixp = fixp;
prev_insn_reloc_type = reloc_type;
if (mips16)
prev_insn_extended = (ip->use_extend
|| reloc_type > BFD_RELOC_UNUSED);
}
prev_prev_insn_unreordered = prev_insn_unreordered;
prev_insn_unreordered = 0;
prev_insn_frag = frag_now;
prev_insn_where = f - frag_now->fr_literal;
prev_insn_fixp = fixp;
if (mips16)
prev_insn_extended = ip->use_extend || reloc_type > BFD_RELOC_UNUSED;
prev_insn_valid = 1;
}
else
{
/* We need to record a bit of uninformation even when we are not
reordering, in order to determine the base address for mips16
PC relative relocs. */
prev_insn = *ip;
prev_insn_reloc_type = reloc_type;
}
/* We just output an insn, so the next one doesn't have a label. */
insn_label = NULL;
@ -1874,6 +1903,7 @@ mips_no_prev_insn ()
prev_insn_is_delay_slot = 0;
prev_insn_unreordered = 0;
prev_insn_extended = 0;
prev_insn_reloc_type = BFD_RELOC_UNUSED;
prev_prev_insn_unreordered = 0;
insn_label = NULL;
}
@ -9163,7 +9193,20 @@ mips16_extended_frag (fragp, sec, stretch)
val += stretch;
}
addr = fragp->fr_address + fragp->fr_fix + 2;
addr = fragp->fr_address + fragp->fr_fix;
/* The base address rules are complicated. The base address of
a branch is the following instruction. The base address of a
PC relative load or add is the instruction itself, but if it
is extended add 2, and if it is in a delay slot (in which
case it can not be extended) use the address of the
instruction whose delay slot it is in. */
if (type == 'p' || type == 'q')
addr += 2;
else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
addr -= 4;
else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
addr -= 2;
/* If we are currently assuming that this frag should be
extended, then the current address is two bytes higher. */
@ -9558,11 +9601,26 @@ md_convert_frag (abfd, asec, fragp)
{
addressT addr;
addr = fragp->fr_address + fragp->fr_fix + 2;
addr = fragp->fr_address + fragp->fr_fix;
/* The rules for the base address of a PC relative reloc are
complicated; see mips16_extended_frag. */
if (type == 'p' || type == 'q')
addr += 2;
else if (RELAX_MIPS16_JAL_DSLOT (fragp->fr_subtype))
addr -= 4;
else if (RELAX_MIPS16_DSLOT (fragp->fr_subtype))
addr -= 2;
if (ext)
addr += 2;
addr &= ~ (addressT) ((1 << op->shift) - 1);
val -= addr;
/* Make sure the section winds up with the alignment we have
assumed. */
if (op->shift > 0)
record_alignment (asec, op->shift);
}
buf = (bfd_byte *) (fragp->fr_literal + fragp->fr_fix);