[PATCH] Scale DW_CFA_advance_loc[124] output values

Jakub Jelinek jakub@redhat.com
Wed Nov 19 16:24:00 GMT 2008


On Wed, Nov 19, 2008 at 10:00:19AM -0500, John David Anglin wrote:
> > > I'm thinking the optimization in check_eh_frame is only valid when
> > > the code alignment factor is 1.  That's the only time the advance
> > > can be represented as a difference of symbols.
> > 
> > The optimization is valid for any code alignment factor, just it behaves
> > incorrectly ATM for factor > 1.
> 
> The file was written to optimize GCC generated EH data and I believe
> GCC hard codes the factor to 1.  So, fixing this optimization is less
> pressing than the other bug.
> 
> Jakub, would you take this?  I only have time for GCC work on weekends.

Here is a fix.  Tested on the t{,2}.s files I've posted, plus slightly
modified alternatives (b 1f; .align 4; 1: instead of the 2 nops) and
using >>2 instead of /4.

2008-11-19  Jakub Jelinek  <jakub@redhat.com>

	* Makefile.am (ehopt.o): Add struc-symbol.h.
	* Makefile.in: Regenerated.
	* ehopt.c: Include struc-symbol.h.
	(check_eh_frame): For very small O_constant DW_CFA_advance_loc4
	create correct DW_CFA_advance_loc.  Handle O_subtract only
	for code alignment factor 1, otherwise handle O_divide or
	O_right_shift of O_subtract and O_constant.
	(eh_frame_estimate_size_before_relax): Always divide by ca.
	(eh_frame_convert_frag): Likewise.

--- gas/Makefile.am.jj	2008-11-19 15:50:40.000000000 +0100
+++ gas/Makefile.am	2008-11-19 16:57:49.000000000 +0100
@@ -2159,7 +2159,8 @@ dwarf2dbg.o: dwarf2dbg.c $(INCDIR)/safe-
 dw2gencfi.o: dw2gencfi.c dw2gencfi.h $(INCDIR)/elf/dwarf2.h \
   subsegs.h $(INCDIR)/obstack.h
 ecoff.o: ecoff.c ecoff.h
-ehopt.o: ehopt.c subsegs.h $(INCDIR)/obstack.h $(INCDIR)/elf/dwarf2.h
+ehopt.o: ehopt.c subsegs.h $(INCDIR)/obstack.h $(INCDIR)/elf/dwarf2.h \
+  struc-symbol.h
 expr.o: expr.c $(INCDIR)/safe-ctype.h $(INCDIR)/obstack.h
 flonum-copy.o: flonum-copy.c
 flonum-konst.o: flonum-konst.c
--- gas/Makefile.in.jj	2008-11-19 15:50:40.000000000 +0100
+++ gas/Makefile.in	2008-11-19 16:58:03.000000000 +0100
@@ -3015,7 +3015,8 @@ dwarf2dbg.o: dwarf2dbg.c $(INCDIR)/safe-
 dw2gencfi.o: dw2gencfi.c dw2gencfi.h $(INCDIR)/elf/dwarf2.h \
   subsegs.h $(INCDIR)/obstack.h
 ecoff.o: ecoff.c ecoff.h
-ehopt.o: ehopt.c subsegs.h $(INCDIR)/obstack.h $(INCDIR)/elf/dwarf2.h
+ehopt.o: ehopt.c subsegs.h $(INCDIR)/obstack.h $(INCDIR)/elf/dwarf2.h \
+  struc-symbol.h
 expr.o: expr.c $(INCDIR)/safe-ctype.h $(INCDIR)/obstack.h
 flonum-copy.o: flonum-copy.c
 flonum-konst.o: flonum-konst.c
--- gas/ehopt.c.jj	2007-12-28 09:31:47.000000000 +0100
+++ gas/ehopt.c	2008-11-19 17:03:48.000000000 +0100
@@ -1,5 +1,6 @@
 /* ehopt.c--optimize gcc exception frame information.
-   Copyright 1998, 2000, 2001, 2003, 2005, 2007 Free Software Foundation, Inc.
+   Copyright 1998, 2000, 2001, 2003, 2005, 2007, 2008
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@cygnus.com>.
 
    This file is part of GAS, the GNU Assembler.
@@ -21,6 +22,7 @@
 
 #include "as.h"
 #include "subsegs.h"
+#include "struc-symbol.h"
 
 /* We include this ELF file, even though we may not be assembling for
    ELF, since the exception frame information is always in a format
@@ -398,13 +400,10 @@ check_eh_frame (expressionS *exp, unsign
 	     subtracted were in the same frag and the expression was
 	     reduced to a constant.  We can do the optimization entirely
 	     in this function.  */
-	  if (d->cie_info.code_alignment > 0
-	      && exp->X_add_number % d->cie_info.code_alignment == 0
-	      && exp->X_add_number / d->cie_info.code_alignment < 0x40)
+	  if (exp->X_add_number < 0x40)
 	    {
 	      d->loc4_frag->fr_literal[d->loc4_fix]
-		= DW_CFA_advance_loc
-		  | (exp->X_add_number / d->cie_info.code_alignment);
+		= DW_CFA_advance_loc | exp->X_add_number;
 	      /* No more bytes needed.  */
 	      return 1;
 	    }
@@ -419,23 +418,39 @@ check_eh_frame (expressionS *exp, unsign
 	      *pnbytes = 2;
 	    }
 	}
-      else if (exp->X_op == O_subtract)
+      else if (exp->X_op == O_subtract && d->cie_info.code_alignment == 1)
 	{
 	  /* This is a case we can optimize.  The expression was not
 	     reduced, so we can not finish the optimization until the end
 	     of the assembly.  We set up a variant frag which we handle
 	     later.  */
-	  int fr_subtype;
-
-	  if (d->cie_info.code_alignment > 0)
-	    fr_subtype = d->cie_info.code_alignment << 3;
-	  else
-	    fr_subtype = 0;
-
-	  frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp),
+	  frag_var (rs_cfa, 4, 0, 1 << 3, make_expr_symbol (exp),
 		    d->loc4_fix, (char *) d->loc4_frag);
 	  return 1;
 	}
+      else if ((exp->X_op == O_divide
+		|| exp->X_op == O_right_shift)
+	       && d->cie_info.code_alignment > 1)
+	{
+	  if (exp->X_add_symbol->bsym
+	      && exp->X_op_symbol->bsym
+	      && exp->X_add_symbol->sy_value.X_op == O_subtract
+	      && exp->X_op_symbol->sy_value.X_op == O_constant
+	      && ((exp->X_op == O_divide
+		   ? exp->X_op_symbol->sy_value.X_add_number
+		   : (offsetT) 1 << exp->X_op_symbol->sy_value.X_add_number)
+		  == d->cie_info.code_alignment))
+	    {
+	      /* This is a case we can optimize as well.  The expression was
+		 not reduced, so we can not finish the optimization until the
+		 end of the assembly.  We set up a variant frag which we
+		 handle later.  */
+	      frag_var (rs_cfa, 4, 0, d->cie_info.code_alignment << 3,
+			make_expr_symbol (&exp->X_add_symbol->sy_value),
+			d->loc4_fix, (char *) d->loc4_frag);
+	      return 1;
+	    }
+	}
       break;
 
     case state_error:
@@ -459,7 +474,9 @@ eh_frame_estimate_size_before_relax (fra
 
   diff = resolve_symbol_value (frag->fr_symbol);
 
-  if (ca > 0 && diff % ca == 0 && diff / ca < 0x40)
+  assert (ca > 0);
+  diff /= ca;
+  if (diff < 0x40)
     ret = 0;
   else if (diff < 0x100)
     ret = 1;
@@ -496,21 +513,21 @@ eh_frame_convert_frag (fragS *frag)
 {
   offsetT diff;
   fragS *loc4_frag;
-  int loc4_fix;
+  int loc4_fix, ca;
 
   loc4_frag = (fragS *) frag->fr_opcode;
   loc4_fix = (int) frag->fr_offset;
 
   diff = resolve_symbol_value (frag->fr_symbol);
 
+  ca = frag->fr_subtype >> 3;
+  assert (ca > 0);
+  diff /= ca;
   switch (frag->fr_subtype & 7)
     {
     case 0:
-      {
-	int ca = frag->fr_subtype >> 3;
-	assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40);
-	loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca);
-      }
+      assert (diff < 0x40);
+      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | diff;
       break;
 
     case 1:


	Jakub



More information about the Binutils mailing list