]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2007-03-02 Paul Brook <paul@codesourcery.com>
authorPaul Brook <paul@codesourcery.com>
Fri, 2 Mar 2007 18:22:34 +0000 (18:22 +0000)
committerPaul Brook <paul@codesourcery.com>
Fri, 2 Mar 2007 18:22:34 +0000 (18:22 +0000)
gas/
* 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 stretch argument.  Adjust infinite loop check.

gas/testsuite/
* gas/arm/relax_branch_align.d: New test.
* gas/arm/relax_branch_align.s: New test.

gas/ChangeLog
gas/config/tc-arm.c
gas/testsuite/ChangeLog

index e918fc86b3f01cd0ba0f045524b4d90229863c2c..289d1ce790a29a4d565b4bacddd4437888bfa7e7 100644 (file)
@@ -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.
index f0560f558056d337d07f76cf68b0eacb3f823318..9872968b627b33f68a00c5eaccd3e3d078fd30a0 100644 (file)
@@ -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;
 }
 
index 8cd6a6054298750db6cf11b21d18766a33fc138e..f21d9732c13690733774cbf93de4b0f1dce3d223 100644 (file)
@@ -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