Browse Source

2007-03-02 Paul Brook <paul@codesourcery.com>

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.
drow-reverse-20070409-branch
Paul Brook 19 years ago
parent
commit
5e77afaabd
  1. 7
      gas/ChangeLog
  2. 64
      gas/config/tc-arm.c
  3. 5
      gas/testsuite/ChangeLog

7
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> 2007-03-01 Joseph Myers <joseph@codesourcery.com>
* as.c (parse_args): Update copyright date. * as.c (parse_args): Update copyright date.

64
gas/config/tc-arm.c

@ -16525,16 +16525,42 @@ relax_immediate (fragS *fragp, int size, int shift)
offset = fragp->fr_offset; offset = fragp->fr_offset;
/* Force misaligned offsets to 32-bit variant. */ /* Force misaligned offsets to 32-bit variant. */
if (offset & low) if (offset & low)
return -4; return 4;
if (offset & ~mask) if (offset & ~mask)
return 4; return 4;
return 2; 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 /* Return the size of a relaxable adr pseudo-instruction or PC-relative
load. */ load. */
static int static int
relax_adr (fragS *fragp, asection *sec) relax_adr (fragS *fragp, asection *sec, long stretch)
{ {
addressT addr; addressT addr;
offsetT val; offsetT val;
@ -16544,14 +16570,12 @@ relax_adr (fragS *fragp, asection *sec)
|| sec != S_GET_SEGMENT (fragp->fr_symbol)) || sec != S_GET_SEGMENT (fragp->fr_symbol))
return 4; 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 = fragp->fr_address + fragp->fr_fix;
addr = (addr + 4) & ~3; addr = (addr + 4) & ~3;
/* Fix the insn as the 4-byte version if the target address is not /* Force misaligned targets to 32-bit variant. */
sufficiently aligned. This is prevents an infinite loop when two
instructions have contradictory range/alignment requirements. */
if (val & 3) if (val & 3)
return -4; return 4;
val -= addr; val -= addr;
if (val < 0 || val > 1020) if (val < 0 || val > 1020)
return 4; return 4;
@ -16578,7 +16602,7 @@ relax_addsub (fragS *fragp, asection *sec)
size of the offset field in the narrow instruction. */ size of the offset field in the narrow instruction. */
static int static int
relax_branch (fragS *fragp, asection *sec, int bits) relax_branch (fragS *fragp, asection *sec, int bits, long stretch)
{ {
addressT addr; addressT addr;
offsetT val; offsetT val;
@ -16589,7 +16613,7 @@ relax_branch (fragS *fragp, asection *sec, int bits)
|| sec != S_GET_SEGMENT (fragp->fr_symbol)) || sec != S_GET_SEGMENT (fragp->fr_symbol))
return 4; 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; addr = fragp->fr_address + fragp->fr_fix + 4;
val -= addr; val -= addr;
@ -16605,7 +16629,7 @@ relax_branch (fragS *fragp, asection *sec, int bits)
the current size of the frag should change. */ the current size of the frag should change. */
int int
arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) arm_relax_frag (asection *sec, fragS *fragp, long stretch)
{ {
int oldsize; int oldsize;
int newsize; int newsize;
@ -16614,7 +16638,7 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
switch (fragp->fr_subtype) switch (fragp->fr_subtype)
{ {
case T_MNEM_ldr_pc2: case T_MNEM_ldr_pc2:
newsize = relax_adr(fragp, sec); newsize = relax_adr(fragp, sec, stretch);
break; break;
case T_MNEM_ldr_pc: case T_MNEM_ldr_pc:
case T_MNEM_ldr_sp: 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); newsize = relax_immediate(fragp, 5, 0);
break; break;
case T_MNEM_adr: case T_MNEM_adr:
newsize = relax_adr(fragp, sec); newsize = relax_adr(fragp, sec, stretch);
break; break;
case T_MNEM_mov: case T_MNEM_mov:
case T_MNEM_movs: 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); newsize = relax_immediate(fragp, 8, 0);
break; break;
case T_MNEM_b: case T_MNEM_b:
newsize = relax_branch(fragp, sec, 11); newsize = relax_branch(fragp, sec, 11, stretch);
break; break;
case T_MNEM_bcond: case T_MNEM_bcond:
newsize = relax_branch(fragp, sec, 8); newsize = relax_branch(fragp, sec, 8, stretch);
break; break;
case T_MNEM_add_sp: case T_MNEM_add_sp:
case T_MNEM_add_pc: case T_MNEM_add_pc:
@ -16665,14 +16689,18 @@ arm_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
default: default:
abort(); 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); md_convert_frag (sec->owner, sec, fragp);
frag_wane(fragp); frag_wane(fragp);
return -(newsize + oldsize);
} }
fragp->fr_var = newsize;
return newsize - oldsize; return newsize - oldsize;
} }

5
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> 2007-02-28 Nick Clifton <nickc@redhat.com>
PR gas/3797 PR gas/3797

Loading…
Cancel
Save