mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-26 05:20:30 +00:00
* config/tc-mips.h (mips_relax_frag): Take segment as argument.
(md_relax_frag): Adjust macro. * config/tc-mips.c (mips_relax_branch): New variable. (RELAX_BRANCH_ENCODE, RELAX_BRANCH_P, RELAX_BRANCH_LIKELY, RELAX_BRANCH_LINK, RELAX_BRANCH_TOOBAR): New. (RELAX_MIPS16_P): Adjust. (append_insn): Emit branch to non-constant in a frag_var if branch-relaxation is desirable and possible. (OPTION_RELAX_BRANCH, OPTION_NO_RELAX_BRANCH): New options. (OPTION_ELF_BASE): Adjust. (md_parse_option): Handle new options. (md_apply_fix3): Update comment on EMBEDDED_PIC conditional branch relaxation. (relaxed_branch_length): New function. (md_estimate_size_before_relax): Handle branch frags. (mips_relax_frag): Likewise. (md_convert_frag): Handle branch frags. Warn if branch is relaxed.
This commit is contained in:
parent
e2b23ee922
commit
4a6a3df43d
@ -1,3 +1,24 @@
|
|||||||
|
2002-10-12 Alexandre Oliva <aoliva@redhat.com>
|
||||||
|
|
||||||
|
* config/tc-mips.h (mips_relax_frag): Take segment as argument.
|
||||||
|
(md_relax_frag): Adjust macro.
|
||||||
|
* config/tc-mips.c (mips_relax_branch): New variable.
|
||||||
|
(RELAX_BRANCH_ENCODE, RELAX_BRANCH_P, RELAX_BRANCH_LIKELY,
|
||||||
|
RELAX_BRANCH_LINK, RELAX_BRANCH_TOOBAR): New.
|
||||||
|
(RELAX_MIPS16_P): Adjust.
|
||||||
|
(append_insn): Emit branch to non-constant in a frag_var if
|
||||||
|
branch-relaxation is desirable and possible.
|
||||||
|
(OPTION_RELAX_BRANCH, OPTION_NO_RELAX_BRANCH): New options.
|
||||||
|
(OPTION_ELF_BASE): Adjust.
|
||||||
|
(md_parse_option): Handle new options.
|
||||||
|
(md_apply_fix3): Update comment on EMBEDDED_PIC conditional
|
||||||
|
branch relaxation.
|
||||||
|
(relaxed_branch_length): New function.
|
||||||
|
(md_estimate_size_before_relax): Handle branch frags.
|
||||||
|
(mips_relax_frag): Likewise.
|
||||||
|
(md_convert_frag): Handle branch frags. Warn if branch is
|
||||||
|
relaxed.
|
||||||
|
|
||||||
2002-10-11 Kaz Kojima <kkojima@rr.iij4u.or.jp>
|
2002-10-11 Kaz Kojima <kkojima@rr.iij4u.or.jp>
|
||||||
|
|
||||||
* config/tc-sh.c (sh_force_relocation): Make sure TLS relocs get
|
* config/tc-sh.c (sh_force_relocation): Make sure TLS relocs get
|
||||||
|
@ -563,6 +563,13 @@ static const unsigned int mips16_to_32_reg_map[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int mips_fix_4122_bugs;
|
static int mips_fix_4122_bugs;
|
||||||
|
|
||||||
|
/* We don't relax branches by default, since this causes us to expand
|
||||||
|
`la .l2 - .l1' if there's a branch between .l1 and .l2, because we
|
||||||
|
fail to compute the offset before expanding the macro to the most
|
||||||
|
efficient expansion. */
|
||||||
|
|
||||||
|
static int mips_relax_branch;
|
||||||
|
|
||||||
/* Since the MIPS does not have multiple forms of PC relative
|
/* Since the MIPS does not have multiple forms of PC relative
|
||||||
instructions, we do not have to do relaxing as is done on other
|
instructions, we do not have to do relaxing as is done on other
|
||||||
@ -640,6 +647,88 @@ static int mips_fix_4122_bugs;
|
|||||||
#define RELAX_RELOC3(i) (((i) >> 1) & 1)
|
#define RELAX_RELOC3(i) (((i) >> 1) & 1)
|
||||||
#define RELAX_WARN(i) ((i) & 1)
|
#define RELAX_WARN(i) ((i) & 1)
|
||||||
|
|
||||||
|
/* Branch without likely bit. If label is out of range, we turn:
|
||||||
|
|
||||||
|
beq reg1, reg2, label
|
||||||
|
delay slot
|
||||||
|
|
||||||
|
into
|
||||||
|
|
||||||
|
bne reg1, reg2, 0f
|
||||||
|
nop
|
||||||
|
j label
|
||||||
|
0: delay slot
|
||||||
|
|
||||||
|
with the following opcode replacements:
|
||||||
|
|
||||||
|
beq <-> bne
|
||||||
|
blez <-> bgtz
|
||||||
|
bltz <-> bgez
|
||||||
|
bc1f <-> bc1t
|
||||||
|
|
||||||
|
bltzal <-> bgezal (with jal label instead of j label)
|
||||||
|
|
||||||
|
Even though keeping the delay slot instruction in the delay slot of
|
||||||
|
the branch would be more efficient, it would be very tricky to do
|
||||||
|
correctly, because we'd have to introduce a variable frag *after*
|
||||||
|
the delay slot instruction, and expand that instead. Let's do it
|
||||||
|
the easy way for now, even if the branch-not-taken case now costs
|
||||||
|
one additional instruction. Out-of-range branches are not supposed
|
||||||
|
to be common, anyway.
|
||||||
|
|
||||||
|
Branch likely. If label is out of range, we turn:
|
||||||
|
|
||||||
|
beql reg1, reg2, label
|
||||||
|
delay slot (annulled if branch not taken)
|
||||||
|
|
||||||
|
into
|
||||||
|
|
||||||
|
beql reg1, reg2, 1f
|
||||||
|
nop
|
||||||
|
beql $0, $0, 2f
|
||||||
|
nop
|
||||||
|
1: j[al] label
|
||||||
|
delay slot (executed only if branch taken)
|
||||||
|
2:
|
||||||
|
|
||||||
|
It would be possible to generate a shorter sequence by losing the
|
||||||
|
likely bit, generating something like:
|
||||||
|
|
||||||
|
bne reg1, reg2, 0f
|
||||||
|
nop
|
||||||
|
j[al] label
|
||||||
|
delay slot (executed only if branch taken)
|
||||||
|
0:
|
||||||
|
|
||||||
|
beql -> bne
|
||||||
|
bnel -> beq
|
||||||
|
blezl -> bgtz
|
||||||
|
bgtzl -> blez
|
||||||
|
bltzl -> bgez
|
||||||
|
bgezl -> bltz
|
||||||
|
bc1fl -> bc1t
|
||||||
|
bc1tl -> bc1f
|
||||||
|
|
||||||
|
bltzall -> bgezal (with jal label instead of j label)
|
||||||
|
bgezall -> bltzal (ditto)
|
||||||
|
|
||||||
|
|
||||||
|
but it's not clear that it would actually improve performance. */
|
||||||
|
#define RELAX_BRANCH_ENCODE(reloc_s2, uncond, likely, link, toofar) \
|
||||||
|
((relax_substateT) \
|
||||||
|
(0xc0000000 \
|
||||||
|
| ((toofar) ? 1 : 0) \
|
||||||
|
| ((link) ? 2 : 0) \
|
||||||
|
| ((likely) ? 4 : 0) \
|
||||||
|
| ((uncond) ? 8 : 0) \
|
||||||
|
| ((reloc_s2) ? 16 : 0)))
|
||||||
|
#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
|
||||||
|
#define RELAX_BRANCH_RELOC_S2(i) (((i) & 16) != 0)
|
||||||
|
#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0)
|
||||||
|
#define RELAX_BRANCH_LIKELY(i) (((i) & 4) != 0)
|
||||||
|
#define RELAX_BRANCH_LINK(i) (((i) & 2) != 0)
|
||||||
|
#define RELAX_BRANCH_TOOFAR(i) (((i) & 1))
|
||||||
|
|
||||||
/* For mips16 code, we use an entirely different form of relaxation.
|
/* For mips16 code, we use an entirely different form of relaxation.
|
||||||
mips16 supports two versions of most instructions which take
|
mips16 supports two versions of most instructions which take
|
||||||
immediate values: a small one which takes some small value, and a
|
immediate values: a small one which takes some small value, and a
|
||||||
@ -667,7 +756,7 @@ static int mips_fix_4122_bugs;
|
|||||||
| ((ext) ? 0x200 : 0) \
|
| ((ext) ? 0x200 : 0) \
|
||||||
| ((dslot) ? 0x400 : 0) \
|
| ((dslot) ? 0x400 : 0) \
|
||||||
| ((jal_dslot) ? 0x800 : 0))
|
| ((jal_dslot) ? 0x800 : 0))
|
||||||
#define RELAX_MIPS16_P(i) (((i) & 0x80000000) != 0)
|
#define RELAX_MIPS16_P(i) (((i) & 0xc0000000) == 0x80000000)
|
||||||
#define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
|
#define RELAX_MIPS16_TYPE(i) ((i) & 0xff)
|
||||||
#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
|
#define RELAX_MIPS16_USER_SMALL(i) (((i) & 0x100) != 0)
|
||||||
#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
|
#define RELAX_MIPS16_USER_EXT(i) (((i) & 0x200) != 0)
|
||||||
@ -785,6 +874,7 @@ static void s_mips_weakext PARAMS ((int));
|
|||||||
static void s_mips_file PARAMS ((int));
|
static void s_mips_file PARAMS ((int));
|
||||||
static void s_mips_loc PARAMS ((int));
|
static void s_mips_loc PARAMS ((int));
|
||||||
static int mips16_extended_frag PARAMS ((fragS *, asection *, long));
|
static int mips16_extended_frag PARAMS ((fragS *, asection *, long));
|
||||||
|
static int relaxed_branch_length (fragS *, asection *, int);
|
||||||
static int validate_mips_insn PARAMS ((const struct mips_opcode *));
|
static int validate_mips_insn PARAMS ((const struct mips_opcode *));
|
||||||
static void show PARAMS ((FILE *, const char *, int *, int *));
|
static void show PARAMS ((FILE *, const char *, int *, int *));
|
||||||
#ifdef OBJ_ELF
|
#ifdef OBJ_ELF
|
||||||
@ -1840,7 +1930,38 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*reloc_type > BFD_RELOC_UNUSED)
|
if (place == NULL
|
||||||
|
&& address_expr
|
||||||
|
&& ((*reloc_type == BFD_RELOC_16_PCREL
|
||||||
|
&& address_expr->X_op != O_constant)
|
||||||
|
|| *reloc_type == BFD_RELOC_16_PCREL_S2)
|
||||||
|
&& (pinfo & INSN_UNCOND_BRANCH_DELAY || pinfo & INSN_COND_BRANCH_DELAY
|
||||||
|
|| pinfo & INSN_COND_BRANCH_LIKELY)
|
||||||
|
&& mips_relax_branch
|
||||||
|
/* Don't try branch relaxation within .set nomacro, or within
|
||||||
|
.set noat if we use $at for PIC computations. If it turns
|
||||||
|
out that the branch was out-of-range, we'll get an error. */
|
||||||
|
&& !mips_opts.warn_about_macros
|
||||||
|
&& !(mips_opts.noat && mips_pic != NO_PIC)
|
||||||
|
&& !mips_opts.mips16)
|
||||||
|
{
|
||||||
|
f = frag_var (rs_machine_dependent,
|
||||||
|
relaxed_branch_length
|
||||||
|
(NULL, NULL,
|
||||||
|
(pinfo & INSN_UNCOND_BRANCH_DELAY) ? -1
|
||||||
|
: (pinfo & INSN_COND_BRANCH_LIKELY) ? 1 : 0), 4,
|
||||||
|
RELAX_BRANCH_ENCODE
|
||||||
|
(*reloc_type == BFD_RELOC_16_PCREL_S2,
|
||||||
|
pinfo & INSN_UNCOND_BRANCH_DELAY,
|
||||||
|
pinfo & INSN_COND_BRANCH_LIKELY,
|
||||||
|
pinfo & INSN_WRITE_GPR_31,
|
||||||
|
0),
|
||||||
|
address_expr->X_add_symbol,
|
||||||
|
address_expr->X_add_number,
|
||||||
|
0);
|
||||||
|
*reloc_type = BFD_RELOC_UNUSED;
|
||||||
|
}
|
||||||
|
else if (*reloc_type > BFD_RELOC_UNUSED)
|
||||||
{
|
{
|
||||||
/* We need to set up a variant frag. */
|
/* We need to set up a variant frag. */
|
||||||
assert (mips_opts.mips16 && address_expr != NULL);
|
assert (mips_opts.mips16 && address_expr != NULL);
|
||||||
@ -10125,8 +10246,12 @@ struct option md_longopts[] =
|
|||||||
#define OPTION_NO_FIX_VR4122 (OPTION_MD_BASE + 38)
|
#define OPTION_NO_FIX_VR4122 (OPTION_MD_BASE + 38)
|
||||||
{"mfix-vr4122-bugs", no_argument, NULL, OPTION_FIX_VR4122},
|
{"mfix-vr4122-bugs", no_argument, NULL, OPTION_FIX_VR4122},
|
||||||
{"no-mfix-vr4122-bugs", no_argument, NULL, OPTION_NO_FIX_VR4122},
|
{"no-mfix-vr4122-bugs", no_argument, NULL, OPTION_NO_FIX_VR4122},
|
||||||
|
#define OPTION_RELAX_BRANCH (OPTION_MD_BASE + 39)
|
||||||
|
#define OPTION_NO_RELAX_BRANCH (OPTION_MD_BASE + 40)
|
||||||
|
{"relax-branch", no_argument, NULL, OPTION_RELAX_BRANCH},
|
||||||
|
{"no-relax-branch", no_argument, NULL, OPTION_NO_RELAX_BRANCH},
|
||||||
#ifdef OBJ_ELF
|
#ifdef OBJ_ELF
|
||||||
#define OPTION_ELF_BASE (OPTION_MD_BASE + 39)
|
#define OPTION_ELF_BASE (OPTION_MD_BASE + 41)
|
||||||
#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
|
#define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0)
|
||||||
{"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
|
{"KPIC", no_argument, NULL, OPTION_CALL_SHARED},
|
||||||
{"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
|
{"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
|
||||||
@ -10335,6 +10460,14 @@ md_parse_option (c, arg)
|
|||||||
mips_fix_4122_bugs = 0;
|
mips_fix_4122_bugs = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPTION_RELAX_BRANCH:
|
||||||
|
mips_relax_branch = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTION_NO_RELAX_BRANCH:
|
||||||
|
mips_relax_branch = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
#ifdef OBJ_ELF
|
#ifdef OBJ_ELF
|
||||||
/* When generating ELF code, we permit -KPIC and -call_shared to
|
/* When generating ELF code, we permit -KPIC and -call_shared to
|
||||||
select SVR4_PIC, and -non_shared to select no PIC. This is
|
select SVR4_PIC, and -non_shared to select no PIC. This is
|
||||||
@ -11186,13 +11319,9 @@ md_apply_fix3 (fixP, valP, seg)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* FIXME. It would be possible in principle to handle
|
/* If we got here, we have branch-relaxation disabled,
|
||||||
conditional branches which overflow. They could be
|
and there's nothing we can do to fix this instruction
|
||||||
transformed into a branch around a jump. This would
|
without turning it into a longer sequence. */
|
||||||
require setting up variant frags for each different
|
|
||||||
branch type. The native MIPS assembler attempts to
|
|
||||||
handle these cases, but it appears to do it
|
|
||||||
incorrectly. */
|
|
||||||
as_bad_where (fixP->fx_file, fixP->fx_line,
|
as_bad_where (fixP->fx_file, fixP->fx_line,
|
||||||
_("Branch out of range"));
|
_("Branch out of range"));
|
||||||
}
|
}
|
||||||
@ -12662,6 +12791,74 @@ mips16_extended_frag (fragp, sec, stretch)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute the length of a branch sequence, and adjust the
|
||||||
|
RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the
|
||||||
|
worst-case length is computed, with UPDATE being used to indicate
|
||||||
|
whether an unconditional (-1), branch-likely (+1) or regular (0)
|
||||||
|
branch is to be computed. */
|
||||||
|
static int
|
||||||
|
relaxed_branch_length (fragp, sec, update)
|
||||||
|
fragS *fragp;
|
||||||
|
asection *sec;
|
||||||
|
int update;
|
||||||
|
{
|
||||||
|
boolean toofar;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
if (fragp
|
||||||
|
&& S_IS_DEFINED (fragp->fr_symbol)
|
||||||
|
&& sec == S_GET_SEGMENT (fragp->fr_symbol))
|
||||||
|
{
|
||||||
|
addressT addr;
|
||||||
|
offsetT val;
|
||||||
|
|
||||||
|
val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
|
||||||
|
|
||||||
|
addr = fragp->fr_address + fragp->fr_fix + 4;
|
||||||
|
|
||||||
|
val -= addr;
|
||||||
|
|
||||||
|
toofar = val < - (0x8000 << 2) || val >= (0x8000 << 2);
|
||||||
|
}
|
||||||
|
else if (fragp)
|
||||||
|
/* If the symbol is not defined or it's in a different segment,
|
||||||
|
assume the user knows what's going on and emit a short
|
||||||
|
branch. */
|
||||||
|
toofar = false;
|
||||||
|
else
|
||||||
|
toofar = true;
|
||||||
|
|
||||||
|
if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
|
||||||
|
fragp->fr_subtype
|
||||||
|
= RELAX_BRANCH_ENCODE (RELAX_BRANCH_RELOC_S2 (fragp->fr_subtype),
|
||||||
|
RELAX_BRANCH_UNCOND (fragp->fr_subtype),
|
||||||
|
RELAX_BRANCH_LIKELY (fragp->fr_subtype),
|
||||||
|
RELAX_BRANCH_LINK (fragp->fr_subtype),
|
||||||
|
toofar);
|
||||||
|
|
||||||
|
length = 4;
|
||||||
|
if (toofar)
|
||||||
|
{
|
||||||
|
if (fragp ? RELAX_BRANCH_LIKELY (fragp->fr_subtype) : (update > 0))
|
||||||
|
length += 8;
|
||||||
|
|
||||||
|
if (mips_pic != NO_PIC)
|
||||||
|
{
|
||||||
|
/* Additional space for PIC loading of target address. */
|
||||||
|
length += 8;
|
||||||
|
if (mips_opts.isa == ISA_MIPS1)
|
||||||
|
/* Additional space for $at-stabilizing nop. */
|
||||||
|
length += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If branch is conditional. */
|
||||||
|
if (fragp ? !RELAX_BRANCH_UNCOND (fragp->fr_subtype) : (update >= 0))
|
||||||
|
length += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
/* Estimate the size of a frag before relaxing. Unless this is the
|
/* Estimate the size of a frag before relaxing. Unless this is the
|
||||||
mips16, we are not really relaxing here, and the final size is
|
mips16, we are not really relaxing here, and the final size is
|
||||||
encoded in the subtype information. For the mips16, we have to
|
encoded in the subtype information. For the mips16, we have to
|
||||||
@ -12675,6 +12872,14 @@ md_estimate_size_before_relax (fragp, segtype)
|
|||||||
int change = 0;
|
int change = 0;
|
||||||
boolean linkonce = false;
|
boolean linkonce = false;
|
||||||
|
|
||||||
|
if (RELAX_BRANCH_P (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
|
||||||
|
fragp->fr_var = relaxed_branch_length (fragp, segtype, false);
|
||||||
|
|
||||||
|
return fragp->fr_var;
|
||||||
|
}
|
||||||
|
|
||||||
if (RELAX_MIPS16_P (fragp->fr_subtype))
|
if (RELAX_MIPS16_P (fragp->fr_subtype))
|
||||||
/* We don't want to modify the EXTENDED bit here; it might get us
|
/* We don't want to modify the EXTENDED bit here; it might get us
|
||||||
into infinite loops. We change it only in mips_relax_frag(). */
|
into infinite loops. We change it only in mips_relax_frag(). */
|
||||||
@ -13049,10 +13254,20 @@ tc_gen_reloc (section, fixp)
|
|||||||
the current size of the frag should change. */
|
the current size of the frag should change. */
|
||||||
|
|
||||||
int
|
int
|
||||||
mips_relax_frag (fragp, stretch)
|
mips_relax_frag (sec, fragp, stretch)
|
||||||
|
asection *sec;
|
||||||
fragS *fragp;
|
fragS *fragp;
|
||||||
long stretch;
|
long stretch;
|
||||||
{
|
{
|
||||||
|
if (RELAX_BRANCH_P (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
offsetT old_var = fragp->fr_var;
|
||||||
|
|
||||||
|
fragp->fr_var = relaxed_branch_length (fragp, sec, true);
|
||||||
|
|
||||||
|
return fragp->fr_var - old_var;
|
||||||
|
}
|
||||||
|
|
||||||
if (! RELAX_MIPS16_P (fragp->fr_subtype))
|
if (! RELAX_MIPS16_P (fragp->fr_subtype))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -13085,6 +13300,216 @@ md_convert_frag (abfd, asec, fragp)
|
|||||||
int old, new;
|
int old, new;
|
||||||
char *fixptr;
|
char *fixptr;
|
||||||
|
|
||||||
|
if (RELAX_BRANCH_P (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
bfd_byte *buf;
|
||||||
|
unsigned long insn;
|
||||||
|
expressionS exp;
|
||||||
|
fixS *fixp;
|
||||||
|
|
||||||
|
buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
|
||||||
|
|
||||||
|
if (target_big_endian)
|
||||||
|
insn = bfd_getb32 (buf);
|
||||||
|
else
|
||||||
|
insn = bfd_getl32 (buf);
|
||||||
|
|
||||||
|
if (!RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
/* We generate a fixup instead of applying it right now
|
||||||
|
because, if there are linker relaxations, we're going to
|
||||||
|
need the relocations. */
|
||||||
|
exp.X_op = O_symbol;
|
||||||
|
exp.X_add_symbol = fragp->fr_symbol;
|
||||||
|
exp.X_add_number = fragp->fr_offset;
|
||||||
|
|
||||||
|
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
|
||||||
|
4, &exp, 1,
|
||||||
|
RELAX_BRANCH_RELOC_S2 (fragp->fr_subtype)
|
||||||
|
? BFD_RELOC_16_PCREL_S2
|
||||||
|
: BFD_RELOC_16_PCREL);
|
||||||
|
fixp->fx_file = fragp->fr_file;
|
||||||
|
fixp->fx_line = fragp->fr_line;
|
||||||
|
|
||||||
|
md_number_to_chars ((char *)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
as_warn_where (fragp->fr_file, fragp->fr_line,
|
||||||
|
_("relaxed out-of-range branch into a jump"));
|
||||||
|
|
||||||
|
if (RELAX_BRANCH_UNCOND (fragp->fr_subtype))
|
||||||
|
goto uncond;
|
||||||
|
|
||||||
|
if (!RELAX_BRANCH_LIKELY (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
/* Reverse the branch. */
|
||||||
|
switch ((insn >> 28) & 0xf)
|
||||||
|
{
|
||||||
|
case 4:
|
||||||
|
/* bc[0-3][tf]l? and bc1any[24][ft] instructions can
|
||||||
|
have the condition reversed by tweaking a single
|
||||||
|
bit, and their opcodes all have 0x4???????. */
|
||||||
|
assert ((insn & 0xf1000000) == 0x41000000);
|
||||||
|
insn ^= 0x00010000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
/* bltz 0x04000000 bgez 0x04010000
|
||||||
|
bltzal 0x04100000 bgezal 0x04110000 */
|
||||||
|
assert ((insn & 0xfc0e0000) == 0x04000000);
|
||||||
|
insn ^= 0x00010000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
/* beq 0x10000000 bne 0x14000000
|
||||||
|
blez 0x18000000 bgtz 0x1c000000 */
|
||||||
|
insn ^= 0x04000000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
/* Clear the and-link bit. */
|
||||||
|
assert ((insn & 0xfc1c0000) == 0x04100000);
|
||||||
|
|
||||||
|
/* bltzal 0x04100000 bgezal 0x04110000
|
||||||
|
bltzall 0x04120000 bgezall 0x04130000 */
|
||||||
|
insn &= ~0x00100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Branch over the branch (if the branch was likely) or the
|
||||||
|
full jump (not likely case). Compute the offset from the
|
||||||
|
current instruction to branch to. */
|
||||||
|
if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
|
||||||
|
i = 16;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* How many bytes in instructions we've already emitted? */
|
||||||
|
i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
|
||||||
|
/* How many bytes in instructions from here to the end? */
|
||||||
|
i = fragp->fr_var - i;
|
||||||
|
}
|
||||||
|
/* Convert to instruction count. */
|
||||||
|
i >>= 2;
|
||||||
|
/* Branch counts from the next instruction. */
|
||||||
|
i--;
|
||||||
|
insn |= i;
|
||||||
|
/* Branch over the jump. */
|
||||||
|
md_number_to_chars ((char *)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
/* Nop */
|
||||||
|
md_number_to_chars ((char*)buf, 0, 4);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
if (RELAX_BRANCH_LIKELY (fragp->fr_subtype))
|
||||||
|
{
|
||||||
|
/* beql $0, $0, 2f */
|
||||||
|
insn = 0x50000000;
|
||||||
|
/* Compute the PC offset from the current instruction to
|
||||||
|
the end of the variable frag. */
|
||||||
|
/* How many bytes in instructions we've already emitted? */
|
||||||
|
i = buf - (bfd_byte *)fragp->fr_literal - fragp->fr_fix;
|
||||||
|
/* How many bytes in instructions from here to the end? */
|
||||||
|
i = fragp->fr_var - i;
|
||||||
|
/* Convert to instruction count. */
|
||||||
|
i >>= 2;
|
||||||
|
/* Don't decrement i, because we want to branch over the
|
||||||
|
delay slot. */
|
||||||
|
|
||||||
|
insn |= i;
|
||||||
|
md_number_to_chars ((char *)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
md_number_to_chars ((char *)buf, 0, 4);
|
||||||
|
buf += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
uncond:
|
||||||
|
if (mips_pic == NO_PIC)
|
||||||
|
{
|
||||||
|
/* j or jal. */
|
||||||
|
insn = (RELAX_BRANCH_LINK (fragp->fr_subtype)
|
||||||
|
? 0x0c000000 : 0x08000000);
|
||||||
|
exp.X_op = O_symbol;
|
||||||
|
exp.X_add_symbol = fragp->fr_symbol;
|
||||||
|
exp.X_add_number = fragp->fr_offset;
|
||||||
|
|
||||||
|
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
|
||||||
|
4, &exp, 0, BFD_RELOC_MIPS_JMP);
|
||||||
|
fixp->fx_file = fragp->fr_file;
|
||||||
|
fixp->fx_line = fragp->fr_line;
|
||||||
|
|
||||||
|
md_number_to_chars ((char*)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* lw/ld $at, <sym>($gp) R_MIPS_GOT16 */
|
||||||
|
insn = HAVE_64BIT_ADDRESSES ? 0xdf810000 : 0x8f810000;
|
||||||
|
exp.X_op = O_symbol;
|
||||||
|
exp.X_add_symbol = fragp->fr_symbol;
|
||||||
|
exp.X_add_number = fragp->fr_offset;
|
||||||
|
|
||||||
|
if (fragp->fr_offset)
|
||||||
|
{
|
||||||
|
exp.X_add_symbol = make_expr_symbol (&exp);
|
||||||
|
exp.X_add_number = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
|
||||||
|
4, &exp, 0, BFD_RELOC_MIPS_GOT16);
|
||||||
|
fixp->fx_file = fragp->fr_file;
|
||||||
|
fixp->fx_line = fragp->fr_line;
|
||||||
|
|
||||||
|
md_number_to_chars ((char*)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
if (mips_opts.isa == ISA_MIPS1)
|
||||||
|
{
|
||||||
|
/* nop */
|
||||||
|
md_number_to_chars ((char*)buf, 0, 4);
|
||||||
|
buf += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* d/addiu $at, $at, <sym> R_MIPS_LO16 */
|
||||||
|
insn = HAVE_64BIT_ADDRESSES ? 0x64210000 : 0x24210000;
|
||||||
|
|
||||||
|
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
|
||||||
|
4, &exp, 0, BFD_RELOC_LO16);
|
||||||
|
fixp->fx_file = fragp->fr_file;
|
||||||
|
fixp->fx_line = fragp->fr_line;
|
||||||
|
|
||||||
|
md_number_to_chars ((char*)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
|
||||||
|
/* j(al)r $at. */
|
||||||
|
if (RELAX_BRANCH_LINK (fragp->fr_subtype))
|
||||||
|
insn = 0x0020f809;
|
||||||
|
else
|
||||||
|
insn = 0x00200008;
|
||||||
|
|
||||||
|
md_number_to_chars ((char*)buf, insn, 4);
|
||||||
|
buf += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (buf == (bfd_byte *)fragp->fr_literal
|
||||||
|
+ fragp->fr_fix + fragp->fr_var);
|
||||||
|
|
||||||
|
fragp->fr_fix += fragp->fr_var;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (RELAX_MIPS16_P (fragp->fr_subtype))
|
if (RELAX_MIPS16_P (fragp->fr_subtype))
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
|
@ -49,8 +49,9 @@ struct expressionS;
|
|||||||
relocation: */
|
relocation: */
|
||||||
#define MAX_GPREL_OFFSET (0x7FF0)
|
#define MAX_GPREL_OFFSET (0x7FF0)
|
||||||
|
|
||||||
#define md_relax_frag(segment, fragp, stretch) mips_relax_frag(fragp, stretch)
|
#define md_relax_frag(segment, fragp, stretch) \
|
||||||
extern int mips_relax_frag PARAMS ((struct frag *, long));
|
mips_relax_frag(segment, fragp, stretch)
|
||||||
|
extern int mips_relax_frag PARAMS ((asection *, struct frag *, long));
|
||||||
|
|
||||||
#define md_undefined_symbol(name) (0)
|
#define md_undefined_symbol(name) (0)
|
||||||
#define md_operand(x)
|
#define md_operand(x)
|
||||||
|
Loading…
Reference in New Issue
Block a user