This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: [patch] MIPS/gas: load/store address overflow on binutils 2.14
- From: Thiemo Seufer <ica2_ts at csv dot ica dot uni-stuttgart dot de>
- To: "Maciej W. Rozycki" <macro at ds2 dot pg dot gda dot pl>
- Cc: binutils at sources dot redhat dot com, Atsushi Nemoto <anemo at mba dot ocn dot ne dot jp>,Thiemo Seufer <ica2_ts at csv dot ica dot uni-stuttgart dot de>
- Date: Fri, 12 Sep 2003 13:43:08 +0200
- Subject: Re: [patch] MIPS/gas: load/store address overflow on binutils 2.14
- References: <Pine.GSO.3.96.1030908223434.27835I-100000@delta.ds2.pg.gda.pl>
Maciej W. Rozycki wrote:
[snip]
> * config/tc-mips.c (IS_ZEXT_32BIT_NUM): New macro to determine if
> a number is a zero-extended 32-bit number or a negation of one.
> (load_register): Simplify range checks for 16-bit and 32-bit
> constants.
> (macro): Permit 32-bit addresses for load/store as qualified by
> IS_ZEXT_32BIT_NUM.
I took a different approach by sign-extending all constants. I think this
is more consistent with the rest of binutils MIPS support (sign-extend
and truncate if appropriate). It also handles the ldst_constoffset case
and removes some more complicated sign-extension tests.
Thiemo
2003-09-12 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
/gas/ChangeLog
* config/tc-mips.c (macro_build_ldst_constoffset): Sign-extend 32-bit
constants. Change the function prototype.
(load_register): Likewise. Simplify the checks for sign-extended
constants.
(macro): Likewise. Adjust macro_build_ldst_constoffset calls.
(s_cprestore): Adjust macro_build_ldst_constoffset call.
--- source-orig/gas/config/tc-mips.c Wed Jul 2 12:57:09 2003
+++ source/gas/config/tc-mips.c Sat Aug 23 05:23:40 2003
@@ -3215,10 +3215,16 @@ macro_build_lui (char *place, int *count
using AT if necessary. */
static void
macro_build_ldst_constoffset (char *place, int *counter, expressionS *ep,
- const char *op, int treg, int breg)
+ const char *op, int treg, int breg, int dbl)
{
assert (ep->X_op == O_constant);
+ /* Sign-extending 32-bit constants makes their handling easier. */
+ if (! dbl
+ && (ep->X_add_number & 0x80000000)
+ && ! (ep->X_add_number & ~(offsetT) 0xffffffff))
+ ep->X_add_number |= ~(offsetT) 0xffffffff;
+
/* Right now, this routine can only handle signed 32-bit contants. */
if (! IS_SEXT_32BIT_NUM(ep->X_add_number))
as_warn (_("operand overflow"));
@@ -3371,12 +3380,14 @@ load_register (int *counter, int reg, ex
if (ep->X_op != O_big)
{
assert (ep->X_op == O_constant);
- if (ep->X_add_number < 0x8000
- && (ep->X_add_number >= 0
- || (ep->X_add_number >= -0x8000
- && (! dbl
- || ! ep->X_unsigned
- || sizeof (ep->X_add_number) > 4))))
+
+ /* Sign-extending 32-bit constants makes their handling easier. */
+ if (! dbl
+ && (ep->X_add_number & 0x80000000)
+ && ! (ep->X_add_number & ~(offsetT) 0xffffffff))
+ ep->X_add_number |= ~(offsetT) 0xffffffff;
+
+ if (IS_SEXT_16BIT_NUM (ep->X_add_number))
{
/* We can handle 16 bit signed values with an addiu to
$zero. No need to ever use daddiu here, since $zero and
@@ -3393,17 +3404,7 @@ load_register (int *counter, int reg, ex
BFD_RELOC_LO16);
return;
}
- else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)
- && (! dbl
- || ! ep->X_unsigned
- || sizeof (ep->X_add_number) > 4
- || (ep->X_add_number & 0x80000000) == 0))
- || ((HAVE_32BIT_GPRS || ! dbl)
- && (ep->X_add_number &~ (offsetT) 0xffffffff) == 0)
- || (HAVE_32BIT_GPRS
- && ! dbl
- && ((ep->X_add_number &~ (offsetT) 0xffffffff)
- == ~ (offsetT) 0xffffffff)))
+ else if ((IS_SEXT_32BIT_NUM (ep->X_add_number)))
{
/* 32 bit values require an lui. */
macro_build (NULL, counter, ep, "lui", "t,u", reg, BFD_RELOC_HI16);
@@ -5440,7 +5441,8 @@ macro (struct mips_cl_insn *ip)
macro_build_ldst_constoffset (NULL, &icnt, &expr1,
ADDRESS_LOAD_INSN,
mips_gp_register,
- mips_frame_reg);
+ mips_frame_reg,
+ HAVE_64BIT_ADDRESSES);
}
}
}
@@ -5591,7 +5593,8 @@ macro (struct mips_cl_insn *ip)
macro_build_ldst_constoffset (NULL, &icnt, &expr1,
ADDRESS_LOAD_INSN,
mips_gp_register,
- mips_frame_reg);
+ mips_frame_reg,
+ HAVE_64BIT_ADDRESSES);
}
}
}
@@ -5781,6 +5784,16 @@ macro (struct mips_cl_insn *ip)
else
fmt = "t,o(b)";
+ /* Sign-extending 32-bit constants makes their handling easier.
+ The HAVE_64BIT_GPRS... part is due to the linux kernel hack
+ described below. */
+ if ((! HAVE_64BIT_ADDRESSES
+ && (! HAVE_64BIT_GPRS && offset_expr.X_op == O_constant))
+ && (offset_expr.X_op == O_constant)
+ && (offset_expr.X_add_number & 0x80000000)
+ && ! (offset_expr.X_add_number & ~(offsetT) 0xffffffff))
+ offset_expr.X_add_number |= ~(offsetT) 0xffffffff;
+
/* For embedded PIC, we allow loads where the offset is calculated
by subtracting a symbol in the current segment from an unknown
symbol, relative to a base register, e.g.:
@@ -5913,10 +5926,10 @@ macro (struct mips_cl_insn *ip)
end up converting the binary to ELF32 for a number of
platforms whose boot loaders don't support ELF64
binaries. */
- if ((offset_expr.X_op != O_constant && HAVE_64BIT_ADDRESSES)
- || (offset_expr.X_op == O_constant
- && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)
- && HAVE_64BIT_ADDRESS_CONSTANTS))
+ if (HAVE_64BIT_ADDRESSES
+ || (HAVE_64BIT_GPRS
+ && offset_expr.X_op == O_constant
+ && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)))
{
p = NULL;
@@ -5963,9 +5976,9 @@ macro (struct mips_cl_insn *ip)
return;
}
- else if (offset_expr.X_op == O_constant
- && !HAVE_64BIT_ADDRESS_CONSTANTS
- && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
+
+ if (offset_expr.X_op == O_constant
+ && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
as_bad (_("load/store address overflow (max 32 bits)"));
if (breg == 0)
@@ -12279,7 +12293,7 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED
ex.X_add_number = mips_cprestore_offset;
macro_build_ldst_constoffset (NULL, &icnt, &ex, ADDRESS_STORE_INSN,
- mips_gp_register, SP);
+ mips_gp_register, SP, HAVE_64BIT_ADDRESSES);
demand_empty_rest_of_line ();
}