diff --git a/gas/ChangeLog b/gas/ChangeLog index 03f5bbbefe..cf501df923 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,8 @@ Mon Dec 9 17:09:42 1996 Ian Lance Taylor + * config/tc-mips.c (mips16_extended_frag): Avoid an infinite loop + when extending because the value is exactly maxtiny + 1. + * config/tc-mips.c (RELAX_MIPS16_ENCODE): Add small and ext arguments, and store them. Adjust other RELAX_MIPS16 macros. (RELAX_MIPS16_USER_SMALL): Define. diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index c1a348e406..954d047052 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -9154,8 +9154,30 @@ mips16_extended_frag (fragp, sec, stretch) /* If any of the shifted bits are set, we must use an extended opcode. If the address depends on the size of this instruction, this can lead to a loop, so we arrange to always - use an extended opcode. */ - if ((val & ((1 << op->shift) - 1)) != 0) + use an extended opcode. We only check this when we are in + the main relaxation loop, when SEC is NULL. */ + if ((val & ((1 << op->shift) - 1)) != 0 && sec == NULL) + { + fragp->fr_subtype = + RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype); + return 1; + } + + /* If we are about to mark a frag as extended because the value + is precisely maxtiny + 1, then there is a chance of an + infinite loop as in the following code: + la $4,foo + .skip 1020 + .align 2 + foo: + In this case when the la is extended, foo is 0x3fc bytes + away, so the la can be shrunk, but then foo is 0x400 away, so + the la must be extended. To avoid this loop, we mark the + frag as extended if it was small, and is about to become + extended with a value of maxtiny + 1. */ + if (val == ((maxtiny + 1) << op->shift) + && ! RELAX_MIPS16_EXTENDED (fragp->fr_subtype) + && sec == NULL) { fragp->fr_subtype = RELAX_MIPS16_MARK_LONG_BRANCH (fragp->fr_subtype);