aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r--gas/config/tc-mips.c116
1 files changed, 84 insertions, 32 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index d3cf055..834ecd9 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -1407,7 +1407,8 @@ reloc_needs_lo_p (bfd_reloc_code_real_type reloc)
{
return (HAVE_IN_PLACE_ADDENDS
&& (reloc == BFD_RELOC_HI16_S
- || reloc == BFD_RELOC_MIPS_GOT16));
+ || reloc == BFD_RELOC_MIPS_GOT16
+ || reloc == BFD_RELOC_MIPS16_HI16_S));
}
/* Return true if the given fixup is followed by a matching R_MIPS_LO16
@@ -1417,7 +1418,8 @@ static inline bfd_boolean
fixup_has_matching_lo_p (fixS *fixp)
{
return (fixp->fx_next != NULL
- && fixp->fx_next->fx_r_type == BFD_RELOC_LO16
+ && (fixp->fx_next->fx_r_type == BFD_RELOC_LO16
+ || fixp->fx_next->fx_r_type == BFD_RELOC_MIPS16_LO16)
&& fixp->fx_addsy == fixp->fx_next->fx_addsy
&& fixp->fx_offset == fixp->fx_next->fx_offset);
}
@@ -2194,7 +2196,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
|| reloc_type[0] == BFD_RELOC_MIPS_HIGHER
|| reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP
|| reloc_type[0] == BFD_RELOC_MIPS_REL16
- || reloc_type[0] == BFD_RELOC_MIPS_RELGOT))
+ || reloc_type[0] == BFD_RELOC_MIPS_RELGOT
+ || reloc_type[0] == BFD_RELOC_MIPS16_GPREL
+ || reloc_type[0] == BFD_RELOC_MIPS16_HI16_S
+ || reloc_type[0] == BFD_RELOC_MIPS16_LO16))
fixp[0]->fx_no_overflow = 1;
if (mips_relax.sequence)
@@ -9097,6 +9102,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
unsigned int regno;
unsigned int lastregno = 0;
char *s_reset;
+ size_t i;
insn_error = NULL;
@@ -9183,8 +9189,34 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
&& *imm_reloc > BFD_RELOC_UNUSED
&& insn->pinfo != INSN_MACRO)
{
+ valueT tmp;
+
+ switch (*offset_reloc)
+ {
+ case BFD_RELOC_MIPS16_HI16_S:
+ tmp = (imm_expr.X_add_number + 0x8000) >> 16;
+ break;
+
+ case BFD_RELOC_MIPS16_HI16:
+ tmp = imm_expr.X_add_number >> 16;
+ break;
+
+ case BFD_RELOC_MIPS16_LO16:
+ tmp = ((imm_expr.X_add_number + 0x8000) & 0xffff)
+ - 0x8000;
+ break;
+
+ case BFD_RELOC_UNUSED:
+ tmp = imm_expr.X_add_number;
+ break;
+
+ default:
+ internalError ();
+ }
+ *offset_reloc = BFD_RELOC_UNUSED;
+
mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED,
- imm_expr.X_add_number, TRUE, mips16_small,
+ tmp, TRUE, mips16_small,
mips16_ext, &ip->insn_opcode,
&ip->use_extend, &ip->extend);
imm_expr.X_op = O_absent;
@@ -9395,47 +9427,43 @@ mips16_ip (char *str, struct mips_cl_insn *ip)
}
break;
- case '<':
- case '>':
- case '[':
- case ']':
- case '4':
case '5':
case 'H':
case 'W':
case 'D':
case 'j':
- case '8':
case 'V':
case 'C':
case 'U':
case 'k':
case 'K':
- if (s[0] == '%'
- && strncmp (s + 1, "gprel(", sizeof "gprel(" - 1) == 0)
+ i = my_getSmallExpression (&imm_expr, imm_reloc, s);
+ if (i > 0)
{
- /* This is %gprel(SYMBOL). We need to read SYMBOL,
- and generate the appropriate reloc. If the text
- inside %gprel is not a symbol name with an
- optional offset, then we generate a normal reloc
- and will probably fail later. */
- my_getExpression (&imm_expr, s + sizeof "%gprel" - 1);
- if (imm_expr.X_op == O_symbol)
+ if (imm_expr.X_op != O_constant)
{
mips16_ext = TRUE;
- *imm_reloc = BFD_RELOC_MIPS16_GPREL;
- s = expr_end;
ip->use_extend = TRUE;
ip->extend = 0;
- continue;
}
+ else
+ {
+ /* We need to relax this instruction. */
+ *offset_reloc = *imm_reloc;
+ *imm_reloc = (int) BFD_RELOC_UNUSED + c;
+ }
+ s = expr_end;
+ continue;
}
- else
- {
- /* Just pick up a normal expression. */
- my_getExpression (&imm_expr, s);
- }
-
+ *imm_reloc = BFD_RELOC_UNUSED;
+ /* Fall through. */
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '4':
+ case '8':
+ my_getExpression (&imm_expr, s);
if (imm_expr.X_op == O_register)
{
/* What we thought was an expression turned out to
@@ -9797,11 +9825,13 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val,
}
}
-static const struct percent_op_match
+struct percent_op_match
{
const char *str;
bfd_reloc_code_real_type reloc;
-} percent_op[] =
+};
+
+static const struct percent_op_match mips_percent_op[] =
{
{"%lo", BFD_RELOC_LO16},
#ifdef OBJ_ELF
@@ -9823,6 +9853,13 @@ static const struct percent_op_match
{"%hi", BFD_RELOC_HI16_S}
};
+static const struct percent_op_match mips16_percent_op[] =
+{
+ {"%lo", BFD_RELOC_MIPS16_LO16},
+ {"%gprel", BFD_RELOC_MIPS16_GPREL},
+ {"%hi", BFD_RELOC_MIPS16_HI16_S}
+};
+
/* Return true if *STR points to a relocation operator. When returning true,
move *STR over the operator and store its relocation code in *RELOC.
@@ -9831,9 +9868,21 @@ static const struct percent_op_match
static bfd_boolean
parse_relocation (char **str, bfd_reloc_code_real_type *reloc)
{
- size_t i;
+ const struct percent_op_match *percent_op;
+ size_t limit, i;
+
+ if (mips_opts.mips16)
+ {
+ percent_op = mips16_percent_op;
+ limit = ARRAY_SIZE (mips16_percent_op);
+ }
+ else
+ {
+ percent_op = mips_percent_op;
+ limit = ARRAY_SIZE (mips_percent_op);
+ }
- for (i = 0; i < ARRAY_SIZE (percent_op); i++)
+ for (i = 0; i < limit; i++)
if (strncasecmp (*str, percent_op[i].str, strlen (percent_op[i].str)) == 0)
{
*str += strlen (percent_op[i].str);
@@ -11000,6 +11049,8 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_MIPS_CALL_HI16:
case BFD_RELOC_MIPS_CALL_LO16:
case BFD_RELOC_MIPS16_GPREL:
+ case BFD_RELOC_MIPS16_HI16:
+ case BFD_RELOC_MIPS16_HI16_S:
assert (! fixP->fx_pcrel);
/* Nothing needed to do. The value comes from the reloc entry */
break;
@@ -11051,6 +11102,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
break;
case BFD_RELOC_LO16:
+ case BFD_RELOC_MIPS16_LO16:
/* FIXME: Now that embedded-PIC is gone, some of this code/comment
may be safe to remove, but if so it's not obvious. */
/* When handling an embedded PIC switch statement, we can wind