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]

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


On Sun, Mar 11, 2007 at 01:37:04PM -0000, amodra at bigpond dot net dot au wrote:
> 
> Yes, we can modify the output, but we must do so in a way that does not confuse
> consumers of .gcc_except_table.  I don't believe changing the .align is correct,
> because data normally follows the .align (a number of .long's before the end
> label).  Changing alignment in a way that cures the uleb128 problem necessarily
> inserts zero bytes, which I think will confuse the unwinder.
> 

I don't think increasing alignment should break any well formed
assembly codes.  This patch breaks the infinite loop by increasing
alignment before the left symbol in leb128.


H.J.
-----
gas/

2007-02-19  H.J. Lu  <hongjiu.lu@intel.com>

	PR gas/4029
	* symbols.c (symbol_get_subtract_frags): New.
	* symbols.h (symbol_get_subtract_frags): Likewise.
	* write.c (relax_segment): Break infinite loop for rs_leb128
	by increasing alignment.

gas/testsuite/

2007-02-19  Alan Modra  <amodra@bigpond.net.au>
	    H.J. Lu  <hongjiu.lu@intel.com>

	PR gas/4029
	* gas/all/gas.exp: Add relax.

	* gas/all/relax.d: New file.
	* gas/all/relax.s: Likewise.

--- gas/symbols.c.relax	2007-03-08 06:16:17.000000000 -0800
+++ gas/symbols.c	2007-03-11 16:59:39.000000000 -0700
@@ -3153,3 +3153,24 @@ symbol_relc_make_expr (expressionS * exp
 }
 
 #endif
+
+/* Get frags of left and right symbols in subtraction.  */
+
+void
+symbol_get_subtract_frags (symbolS *sym, fragS **left, fragS **right)
+{
+  if (sym->sy_value.X_op == O_subtract)
+    {
+      if (left)
+	*left = symbol_get_frag (sym->sy_value.X_add_symbol);
+      if (right)
+	*right = symbol_get_frag (sym->sy_value.X_op_symbol);
+    }
+  else
+    {
+      if (left)
+	*left = NULL;
+      if (right)
+	*right = NULL;
+    }
+}
--- gas/symbols.h.relax	2007-02-05 17:27:16.000000000 -0800
+++ gas/symbols.h	2007-03-11 16:53:37.000000000 -0700
@@ -177,6 +177,7 @@ extern offsetT *symbol_X_add_number (sym
 extern void symbol_set_value_now (symbolS *);
 extern void symbol_set_frag (symbolS *, fragS *);
 extern fragS *symbol_get_frag (symbolS *);
+extern void symbol_get_subtract_frags (symbolS *, fragS **, fragS **);
 extern void symbol_mark_used (symbolS *);
 extern void symbol_clear_used (symbolS *);
 extern int symbol_used_p (symbolS *);
--- gas/testsuite/gas/all/gas.exp.relax	2007-02-06 07:53:27.000000000 -0800
+++ gas/testsuite/gas/all/gas.exp	2007-03-11 17:37:31.000000000 -0700
@@ -264,6 +264,7 @@ if {  ([istarget "i*86-*-*pe*"] && ![ist
 
 run_dump_test assign
 run_dump_test sleb128
+run_dump_test relax
 
 # .quad is 16 bytes on i960.
 if { ![istarget "i960-*-*"] } {
--- gas/testsuite/gas/all/relax.d.relax	2007-03-11 17:27:00.000000000 -0700
+++ gas/testsuite/gas/all/relax.d	2007-03-11 17:31:12.000000000 -0700
@@ -0,0 +1,11 @@
+#objdump : -s -j .data -j "\$DATA\$"
+#name : relax .sleb128
+
+.*: .*
+
+Contents of section (\.data|\$DATA\$):
+ 0000 00008380 01070000 00000000 00000000  ................
+ 0010 00000000 00000000 00000000 00000000  ................
+#...
+ 4000 00000000 00000000                    ........        
+#pass
--- gas/testsuite/gas/all/relax.s.relax	2007-03-11 17:25:51.000000000 -0700
+++ gas/testsuite/gas/all/relax.s	2007-03-11 17:25:37.000000000 -0700
@@ -0,0 +1,9 @@
+ .data
+ .align 4
+ .byte 0, 0
+ .uleb128 end - start
+start:
+  .byte 7
+ .space 128*128 - 3 /* or -2 or -3 */
+ .align 4
+end:
--- gas/write.c.relax	2007-03-01 14:53:14.000000000 -0800
+++ gas/write.c	2007-03-11 17:43:43.000000000 -0700
@@ -1985,6 +1985,7 @@ relax_segment (struct frag *segment_frag
     ret = 0;
     do
       {
+restart:
 	stretch = 0;
 	stretched = 0;
 
@@ -2209,6 +2210,36 @@ relax_segment (struct frag *segment_frag
 		  size = sizeof_leb128 (value, fragP->fr_subtype);
 		  growth = size - fragP->fr_offset;
 		  fragP->fr_offset = size;
+		  if (growth < 0)
+		    {
+		      struct frag *left;
+
+		      /* We started it at size 1.  If it shrinks now,
+			 it means that we will go into an infinite
+			 loop.  We try to adjust aligment before
+			 the left symbol.  */
+		      symbol_get_subtract_frags (fragP->fr_symbol,
+						 &left, NULL);
+		      if (left)
+			{
+			  struct frag *alignP = NULL, *nextP;
+
+			  for (nextP = fragP;
+			       nextP && nextP != left;
+			       nextP = nextP->fr_next)
+			    if (nextP->fr_type == rs_align
+				&& nextP->fr_offset != 0)
+			      alignP = nextP;
+
+			  if (alignP)
+			    {
+			      /* FIXME: Is it 100% safe to increase
+				 alignment?  */
+			      alignP->fr_offset++;
+			      goto restart;
+			    }
+			}
+		    }
 		}
 		break;
 


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