From 43c0598fe7e380d99c9c00f3e45e7da3fa6e1feb Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 23 Sep 2012 09:56:47 +0000 Subject: [PATCH] gas/ * config/tc-mips.c (SEXT_16BIT): New macro. (mips16_immed): Take the reloc type as a parameter. Do not impose a signed vs. unsigned distinction on the value when a relocation operator was used. (mips16_macro_build, mips16_ip, md_convert_frag): Pass the reloc type to mips16_immed. (macro): Use SEXT_16BIT. --- gas/ChangeLog | 10 +++++++++ gas/config/tc-mips.c | 62 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index da66b49..8bbf177 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,15 @@ 2012-09-23 Richard Sandiford + * config/tc-mips.c (SEXT_16BIT): New macro. + (mips16_immed): Take the reloc type as a parameter. Do not impose + a signed vs. unsigned distinction on the value when a relocation + operator was used. + (mips16_macro_build, mips16_ip, md_convert_frag): Pass the reloc + type to mips16_immed. + (macro): Use SEXT_16BIT. + +2012-09-23 Richard Sandiford + * config/tc-mips.c (read_insn, write_insn, read_compressed_insn): New functions. (install_insn, md_apply_fix, md_convert_frag, mips_handle_align): diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 885aaf8..1522487 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1176,6 +1176,9 @@ static int mips_relax_branch; #define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x40000) #define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x40000) +/* Sign-extend 16-bit value X. */ +#define SEXT_16BIT(X) ((((X) + 0x8000) & 0xffff) - 0x8000) + /* Is the given value a sign-extended 32-bit value? */ #define IS_SEXT_32BIT_NUM(x) \ (((x) &~ (offsetT) 0x7fffffff) == 0 \ @@ -1321,7 +1324,8 @@ static void mips16_macro (struct mips_cl_insn * ip); static void mips_ip (char *str, struct mips_cl_insn * ip); static void mips16_ip (char *str, struct mips_cl_insn * ip); static void mips16_immed - (char *, unsigned int, int, offsetT, unsigned int, unsigned long *); + (char *, unsigned int, int, bfd_reloc_code_real_type, offsetT, + unsigned int, unsigned long *); static size_t my_getSmallExpression (expressionS *, bfd_reloc_code_real_type *, char *); static void my_getExpression (expressionS *, char *); @@ -5222,7 +5226,7 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt, *r = (int) BFD_RELOC_UNUSED + c; else { - mips16_immed (NULL, 0, c, ep->X_add_number, + mips16_immed (NULL, 0, c, *r, ep->X_add_number, 0, &insn.insn_opcode); ep = NULL; *r = BFD_RELOC_UNUSED; @@ -7277,7 +7281,7 @@ macro (struct mips_cl_insn *ip) { expr1.X_add_number = offset_expr.X_add_number; offset_expr.X_add_number = - ((offset_expr.X_add_number + 0x8000) & 0xffff) - 0x8000; + SEXT_16BIT (offset_expr.X_add_number); load_got_offset (tempreg, &offset_expr); offset_expr.X_add_number = expr1.X_add_number; /* If we are going to add in a base register, and the @@ -7505,8 +7509,7 @@ macro (struct mips_cl_insn *ip) used_at = 1; } - offset_expr.X_add_number = - ((expr1.X_add_number + 0x8000) & 0xffff) - 0x8000; + offset_expr.X_add_number = SEXT_16BIT (expr1.X_add_number); relax_switch (); if (gpdelay) @@ -13397,12 +13400,13 @@ mips16_ip (char *str, struct mips_cl_insn *ip) default: internalError (); } - *offset_reloc = BFD_RELOC_UNUSED; mips16_immed (NULL, 0, *imm_reloc - BFD_RELOC_UNUSED, - tmp, forced_insn_length, &ip->insn_opcode); + *offset_reloc, tmp, forced_insn_length, + &ip->insn_opcode); imm_expr.X_op = O_absent; *imm_reloc = BFD_RELOC_UNUSED; + *offset_reloc = BFD_RELOC_UNUSED; } return; @@ -13988,11 +13992,16 @@ static const struct mips16_immed_operand mips16_immed_operands[] = extending it if necessary. The instruction in *INSN may already be extended. - TYPE is the type of the immediate field. USER_INSN_LENGTH is the - length that the user requested, or 0 if none. */ + RELOC is the relocation that produced VAL, or BFD_RELOC_UNUSED + if none. In the former case, VAL is a 16-bit number with no + defined signedness. + + TYPE is the type of the immediate field. USER_INSN_LENGTH + is the length that the user requested, or 0 if none. */ static void -mips16_immed (char *file, unsigned int line, int type, offsetT val, +mips16_immed (char *file, unsigned int line, int type, + bfd_reloc_code_real_type reloc, offsetT val, unsigned int user_insn_length, unsigned long *insn) { const struct mips16_immed_operand *op; @@ -14017,11 +14026,15 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val, mintiny = 0; maxtiny = (1 << op->nbits) - 1; } + if (reloc != BFD_RELOC_UNUSED) + val &= 0xffff; } else { mintiny = - (1 << (op->nbits - 1)); maxtiny = (1 << (op->nbits - 1)) - 1; + if (reloc != BFD_RELOC_UNUSED) + val = SEXT_16BIT (val); } /* Branch offsets have an implicit 0 in the lowest bit. */ @@ -14060,19 +14073,22 @@ mips16_immed (char *file, unsigned int line, int type, offsetT val, long minext, maxext; int extval; - if (op->extu) - { - minext = 0; - maxext = (1 << op->extbits) - 1; - } - else + if (reloc == BFD_RELOC_UNUSED) { - minext = - (1 << (op->extbits - 1)); - maxext = (1 << (op->extbits - 1)) - 1; + if (op->extu) + { + minext = 0; + maxext = (1 << op->extbits) - 1; + } + else + { + minext = - (1 << (op->extbits - 1)); + maxext = (1 << (op->extbits - 1)) - 1; + } + if (val < minext || val > maxext) + as_bad_where (file, line, + _("operand value out of range for instruction")); } - if (val < minext || val > maxext) - as_bad_where (file, line, - _("operand value out of range for instruction")); if (op->extbits == 16) { @@ -18263,8 +18279,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) else user_length = 0; - mips16_immed (fragp->fr_file, fragp->fr_line, type, val, - user_length, &insn); + mips16_immed (fragp->fr_file, fragp->fr_line, type, + BFD_RELOC_NONE, val, user_length, &insn); length = (ext ? 4 : 2); gas_assert (mips16_opcode_length (insn) == length); -- 2.7.4