aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog7
-rw-r--r--gas/config/tc-arm.c64
-rw-r--r--gas/testsuite/ChangeLog5
3 files changed, 58 insertions, 18 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index e918fc8..289d1ce 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,10 @@
+2007-03-02 Paul Brook <paul@codesourcery.com>
+
+ * config/tc-arm.c (relax_immediate): Always return positive values.
+ (relaxed_symbol_addr): New function.
+ (relax_adr, relax_branch): Use it.
+ (arm_relax_frag): Pass strect argument. Adjust infinite loop check.
+
2007-03-01 Joseph Myers <joseph@codesourcery.com>
* as.c (parse_args): Update copyright date.
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index f0560f5..9872968 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -16525,16 +16525,42 @@ relax_immediate (fragS *fragp, int size, int shift)
offset = fragp->fr_offset;
/* Force misaligned offsets to 32-bit variant. */
if (offset & low)
- return -4;
+ return 4;
if (offset & ~mask)
return 4;
return 2;
}
+/* Get the address of a symbol during relaxation. */
+static addressT
+relaxed_symbol_addr(fragS *fragp, long stretch)
+{
+ fragS *sym_frag;
+ addressT addr;
+ symbolS *sym;
+
+ sym = fragp->fr_symbol;
+ sym_frag = symbol_get_frag (sym);
+ know (S_GET_SEGMENT (sym) != absolute_section
+ || sym_frag == &zero_address_frag);
+ addr = S_GET_VALUE (sym) + fragp->fr_offset;
+
+ /* If frag has yet to be reached on this pass, assume it will
+ move by STRETCH just as we did. If this is not so, it will
+ be because some frag between grows, and that will force
+ another pass. */
+
+ if (stretch != 0
+ && sym_frag->relax_marker != fragp->relax_marker)
+ addr += stretch;
+
+ return addr;
+}
+
/* Return the size of a relaxable adr pseudo-instruction or PC-relative
load. */
static int
-relax_adr (fragS *fragp, asection *sec)
+relax_adr (fragS *fragp, asection *sec, long stretch)
{
addressT addr;
offsetT val;
@@ -16544,14 +16570,12 @@ relax_adr (fragS *fragp, asection *sec)
|| sec != S_GET_SEGMENT (fragp->fr_symbol))
return 4;
- val = S_GET_VALUE(fragp->fr_symbol) + fragp->fr_offset;
+ val = relaxed_symbol_addr(fragp, stretch);
addr = fragp->fr_address + fragp->fr_fix;
addr = (addr + 4) & ~3;
- /* Fix the insn as the 4-byte version if the target address is not
- sufficiently aligned. This is prevents an infinite loop when two
- instructions have contradictory range/alignment requirements. */
+ /* Force misaligned targets to 32-bit variant. */
if (val & 3)
- return -4;
+ return 4;
val -= addr;
if (val < 0 || val > 1020)
return 4;
@@ -16578,7 +16602,7 @@ relax_addsub (fragS *fragp, asection *sec)
size of the offset field in the narrow instruction. */
static int
-relax_branch (fragS *fragp, asection *sec, int bits)
+relax_branch (fragS *fragp, asection *sec, int bits, long stretch)
{
addressT addr;
offsetT val;
@@ -16589,7 +16613,7 @@ relax_branch (fragS *fragp, asection *sec, int bits)
|| sec != S_GET_SEGMENT (fragp->fr_symbol))
return 4;
- val = S_GET_VALUE(fragp->fr_symbol) + fragp->fr_offset;
+ val = relaxed_symbol_addr(fragp, stretch);
addr = fragp->fr_address + fragp->fr_fix + 4;
val -= addr;
@@ -16605,7 +16629,7 @@ relax_branch (fragS *fragp, asection *sec, int bits)
the current size of the frag should change. */
int
-arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
+arm_relax_frag (asection *sec, fragS *fragp, long stretch)
{
int oldsize;
int newsize;
@@ -16614,7 +16638,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
switch (fragp->fr_subtype)
{
case T_MNEM_ldr_pc2:
- newsize = relax_adr(fragp, sec);
+ newsize = relax_adr(fragp, sec, stretch);
break;
case T_MNEM_ldr_pc:
case T_MNEM_ldr_sp:
@@ -16634,7 +16658,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
newsize = relax_immediate(fragp, 5, 0);
break;
case T_MNEM_adr:
- newsize = relax_adr(fragp, sec);
+ newsize = relax_adr(fragp, sec, stretch);
break;
case T_MNEM_mov:
case T_MNEM_movs:
@@ -16643,10 +16667,10 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
newsize = relax_immediate(fragp, 8, 0);
break;
case T_MNEM_b:
- newsize = relax_branch(fragp, sec, 11);
+ newsize = relax_branch(fragp, sec, 11, stretch);
break;
case T_MNEM_bcond:
- newsize = relax_branch(fragp, sec, 8);
+ newsize = relax_branch(fragp, sec, 8, stretch);
break;
case T_MNEM_add_sp:
case T_MNEM_add_pc:
@@ -16665,14 +16689,18 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
default:
abort();
}
- if (newsize < 0)
+
+ fragp->fr_var = newsize;
+ /* Freeze wide instructions that are at or before the same location as
+ in the previous pass. This avoids infinite loops.
+ Don't freeze them unconditionally because targets may be artificialy
+ misaligned by the expansion of preceeding frags. */
+ if (stretch <= 0 && newsize > 2)
{
- fragp->fr_var = -newsize;
md_convert_frag (sec->owner, sec, fragp);
frag_wane(fragp);
- return -(newsize + oldsize);
}
- fragp->fr_var = newsize;
+
return newsize - oldsize;
}
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 8cd6a60..f21d973 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2007-03-02 Paul Brook <paul@codesourcery.com>
+
+ * gas/arm/relax_branch_align.d: New test.
+ * gas/arm/relax_branch_align.s: New test.
+
2007-02-28 Nick Clifton <nickc@redhat.com>
PR gas/3797