This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PATCH: [Bug gas/4029] relax_segment can't stabilize .gcc_except_table
- From: "H. J. Lu" <hjl at lucon dot org>
- To: binutils at sources dot redhat dot com
- Date: Sun, 11 Mar 2007 17:51:49 -0700
- Subject: 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;