This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PATCH: [Bug gas/4029] relax_segment can't stabilize .gcc_except_table


This differs from the patch I posted previously in that the new
rs_fill padding uses the same fill pattern as the rs_align.

gas/
	PR 4029
	* write.c (relax_segment): Insert extra alignment padding
	to break infinite relax loop when given impossible
	gcc_except_table assembly.

gas/testsuite/
	PR 4029
	* gas/all/relax.s: New.
	* gas/all/relax.d: New.
	* gas/all/gas.exp: Run it.

Index: gas/write.c
===================================================================
RCS file: /cvs/src/src/gas/write.c,v
retrieving revision 1.110
diff -u -p -r1.110 write.c
--- gas/write.c	22 Feb 2007 05:54:51 -0000	1.110
+++ gas/write.c	14 Mar 2007 10:51:12 -0000
@@ -1960,13 +1960,38 @@ relax_segment (struct frag *segment_frag
   /* Do relax().  */
   {
     unsigned long max_iterations;
-    offsetT stretch;	/* May be any size, 0 or negative.  */
-    /* Cumulative number of addresses we have relaxed this pass.
-       We may have relaxed more than one address.  */
-    int stretched;	/* Have we stretched on this pass?  */
-    /* This is 'cuz stretch may be zero, when, in fact some piece of code
-       grew, and another shrank.  If a branch instruction doesn't fit anymore,
-       we could be scrod.  */
+
+    /* Cumulative address adjustment.  */
+    offsetT stretch;
+
+    /* Have we made any adjustment this pass?  We can't just test
+       stretch because one piece of code may have grown and another
+       shrank.  */
+    int stretched;
+
+    /* Most horrible, but gcc may give us some exception data that
+       is impossible to assemble, of the form
+
+       .align 4
+       .byte 0, 0
+       .uleb128 end - start
+       start:
+       .space 128*128 - 1
+       .align 4
+       end:
+
+       If the leb128 is two bytes in size, then end-start is 128*128,
+       which requires a three byte leb128.  If the leb128 is three
+       bytes in size, then end-start is 128*128-1, which requires a
+       two byte leb128.  We work around this dilemma by inserting
+       an extra 4 bytes of alignment just after the .align.  This
+       works because the data after the align is accessed relative to
+       the end label.
+
+       This counter is used in a tiny state machine to detect
+       whether a leb128 followed by an align is impossible to
+       relax.  */
+    int rs_leb128_fudge = 0;
 
     /* We want to prevent going into an infinite loop where one frag grows
        depending upon the location of a symbol which is in turn moved by
@@ -2089,6 +2114,49 @@ relax_segment (struct frag *segment_frag
 		    }
 
 		  growth = newoff - oldoff;
+
+		  /* If this align happens to follow a leb128 and
+		     we have determined that the leb128 is bouncing
+		     in size, then break the cycle by inserting an
+		     extra alignment.  */
+		  if (growth < 0
+		      && (rs_leb128_fudge & 16) != 0
+		      && (rs_leb128_fudge & 15) >= 2)
+		    {
+		      segment_info_type *seginfo = seg_info (segment);
+		      struct obstack *ob = &seginfo->frchainP->frch_obstack;
+		      struct frag *newf;
+
+		      newf = frag_alloc (ob);
+		      obstack_blank_fast (ob, fragP->fr_var);
+		      obstack_finish (ob);
+		      memcpy (newf, fragP, SIZEOF_STRUCT_FRAG);
+		      memcpy (newf->fr_literal,
+			      fragP->fr_literal + fragP->fr_fix,
+			      fragP->fr_var);
+		      newf->fr_type = rs_fill;
+		      newf->fr_fix = 0;
+		      newf->fr_offset = (((offsetT) 1 << fragP->fr_offset)
+					 / fragP->fr_var);
+		      if (newf->fr_offset * newf->fr_var
+			  != (offsetT) 1 << fragP->fr_offset)
+			{
+			  newf->fr_offset = (offsetT) 1 << fragP->fr_offset;
+			  newf->fr_var = 1;
+			}
+		      /* Include growth of new frag, because rs_fill
+			 frags don't normally grow.  */
+		      growth += newf->fr_offset * newf->fr_var;
+		      /* The new frag address is newoff.  Adjust this
+			 for the amount we'll add when we process the
+			 new frag.  */
+		      newf->fr_address = newoff - stretch - growth;
+		      newf->relax_marker ^= 1;
+		      fragP->fr_next = newf;
+#ifdef DEBUG
+		      as_warn (_("padding added"));
+#endif
+		    }
 		}
 		break;
 
@@ -2228,8 +2296,23 @@ relax_segment (struct frag *segment_frag
 	      {
 		stretch += growth;
 		stretched = 1;
+		if (fragP->fr_type == rs_leb128)
+		  rs_leb128_fudge += 16;
+		else if (fragP->fr_type == rs_align
+			 && (rs_leb128_fudge & 16) != 0
+			 && stretch == 0)
+		  rs_leb128_fudge += 16;
+		else
+		  rs_leb128_fudge = 0;
 	      }
 	  }
+
+	if (stretch == 0
+	    && (rs_leb128_fudge & 16) == 0
+	    && (rs_leb128_fudge & -16) != 0)
+	  rs_leb128_fudge += 1;
+	else
+	  rs_leb128_fudge = 0;
       }
     /* Until nothing further to relax.  */
     while (stretched && -- max_iterations);
Index: gas/testsuite/gas/all/gas.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/all/gas.exp,v
retrieving revision 1.44
diff -u -p -r1.44 gas.exp
--- gas/testsuite/gas/all/gas.exp	6 Feb 2007 15:13:26 -0000	1.44
+++ gas/testsuite/gas/all/gas.exp	14 Mar 2007 10:51:17 -0000
@@ -265,6 +265,11 @@ if {  ([istarget "i*86-*-*pe*"] && ![ist
 run_dump_test assign
 run_dump_test sleb128
 
+# .byte is 32 bits on tic4x, and .p2align isn't supported on tic54x
+if { ![istarget "tic4x*-*-*"] && ![istarget "tic54x*-*-*"] } {
+    run_dump_test relax
+}
+
 # .quad is 16 bytes on i960.
 if { ![istarget "i960-*-*"] } {
     run_dump_test quad
Index: gas/testsuite/gas/all/relax.d
===================================================================
RCS file: gas/testsuite/gas/all/relax.d
diff -N gas/testsuite/gas/all/relax.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/all/relax.d	14 Mar 2007 10:51:17 -0000
@@ -0,0 +1,13 @@
+#objdump : -s -j .data -j "\$DATA\$"
+#name : relax .uleb128
+
+.*: .*
+
+Contents of section .*
+ 0000 01020381 01000000 00000000 00000000.*
+#...
+ 0080 00000004 ffff0500 06078380 01000000.*
+#...
+ 4080 00000000 00000000 00000008 ffffffff.*
+ 4090 09090909 09090909 09090909 09090909.*
+#pass
Index: gas/testsuite/gas/all/relax.s
===================================================================
RCS file: gas/testsuite/gas/all/relax.s
diff -N gas/testsuite/gas/all/relax.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gas/testsuite/gas/all/relax.s	14 Mar 2007 10:51:17 -0000
@@ -0,0 +1,20 @@
+ .data
+ .byte 1, 2, 3
+ .uleb128 L2 - L1
+L1:
+ .space 128 - 2
+ .byte 4
+ .p2align 1, 0xff
+L2:
+ .byte 5
+
+ .p2align 2
+ .byte 6, 7
+ .uleb128 L4 - L3
+L3:
+ .space 128*128 - 2
+ .byte 8
+ .p2align 2, 0xff
+L4:
+ .byte 9
+ .p2align 4, 9

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]