diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 9 | ||||
-rw-r--r-- | gas/config/tc-ppc.c | 70 |
2 files changed, 46 insertions, 33 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 8b471d5..95dfaa4 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +2007-05-26 Alan Modra <amodra@bigpond.net.au> + + * config/tc-ppc.c (ppc_insert_operand): Truncate sign bits in + top 32 bits of 64 bit value if so doing results in passing + range check. Rewrite sign extension fudges similarly. Enable + fudges for powerpc64 too. Report user value if range check + fails rather than fudged value. Negate PPC_OPERAND_NEGATIVE + range rather than value, also to report user value on failure. + 2007-03-25 Paul Brook <paul@codesourcery.com> * config/tc-arm.c (T2_SUBS_PC_LR): Define. diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index 96f165c..b07306e 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -86,9 +86,6 @@ static bfd_boolean reg_names_p = TARGET_REG_NAMES_P; static bfd_boolean register_name PARAMS ((expressionS *)); static void ppc_set_cpu PARAMS ((void)); -static unsigned long ppc_insert_operand - PARAMS ((unsigned long insn, const struct powerpc_operand *operand, - offsetT val, char *file, unsigned int line)); static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro)); static void ppc_byte PARAMS ((int)); @@ -1507,15 +1504,13 @@ ppc_cleanup () /* Insert an operand value into an instruction. */ static unsigned long -ppc_insert_operand (insn, operand, val, file, line) - unsigned long insn; - const struct powerpc_operand *operand; - offsetT val; - char *file; - unsigned int line; +ppc_insert_operand (unsigned long insn, + const struct powerpc_operand *operand, + offsetT val, + char *file, + unsigned int line) { long min, max, right; - offsetT test; max = operand->bitm; right = max & -max; @@ -1526,35 +1521,44 @@ ppc_insert_operand (insn, operand, val, file, line) if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0) max = (max >> 1) & -right; min = ~max & -right; - - if (!ppc_obj64) - { - /* Some people write 32 bit hex constants with the sign - extension done by hand. This shouldn't really be - valid, but, to permit this code to assemble on a 64 - bit host, we sign extend the 32 bit value. */ - if (val > 0 - && (val & (offsetT) 0x80000000) != 0 - && (val & (offsetT) 0xffffffff) == val) - { - val -= 0x80000000; - val -= 0x80000000; - } - } } if ((operand->flags & PPC_OPERAND_PLUS1) != 0) max++; if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) - test = - val; - else - test = val; - - if ((min <= max && (test < (offsetT) min || test > (offsetT) max)) - || (test & (right - 1)) != 0) - as_bad_value_out_of_range (_("operand"), - test, (offsetT) min, (offsetT) max, file, line); + { + long tmp = min; + min = -max; + max = -tmp; + } + + if (min <= max) + { + /* Some people write constants with the sign extension done by + hand but only up to 32 bits. This shouldn't really be valid, + but, to permit this code to assemble on a 64-bit host, we + sign extend the 32-bit value to 64 bits if so doing makes the + value valid. */ + if (val > max + && (offsetT) (val - 0x80000000 - 0x80000000) >= min + && (offsetT) (val - 0x80000000 - 0x80000000) <= max + && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0) + val = val - 0x80000000 - 0x80000000; + + /* Similarly, people write expressions like ~(1<<15), and expect + this to be OK for a 32-bit unsigned value. */ + else if (val < min + && (offsetT) (val + 0x80000000 + 0x80000000) >= min + && (offsetT) (val + 0x80000000 + 0x80000000) <= max + && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0) + val = val + 0x80000000 + 0x80000000; + + else if (val < min + || val > max + || (val & (right - 1)) != 0) + as_bad_value_out_of_range (_("operand"), val, min, max, file, line); + } if (operand->insert) { |