2000-11-09 Kazu Hirata <kazu@hxi.com>
[deliverable/binutils-gdb.git] / gas / ehopt.c
index efc9337a3435086d9559bd1bd5b1d07e94b9ee5a..03d7a0416098c3df47e4f3dcc46cb0d020c2159d 100644 (file)
@@ -1,5 +1,5 @@
 /* ehopt.c--optimize gcc exception frame information.
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@cygnus.com>.
 
 This file is part of GAS, the GNU Assembler.
@@ -17,7 +17,7 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with GAS; see the file COPYING.  If not, write to the Free
 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+02111-1307, USA.  */
 
 #include "as.h"
 #include "subsegs.h"
@@ -97,7 +97,8 @@ eh_frame_code_alignment ()
   fragS *f;
   fixS *fix;
   int offset;
-  int eh_state;
+  char augmentation[10];
+  int iaug;
 
   if (code_alignment != 0)
     return code_alignment;
@@ -107,8 +108,16 @@ eh_frame_code_alignment ()
   current_seg = now_seg;
   current_subseg = now_subseg;
   subseg_new (".eh_frame", 0);
+#if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS)
   f = seg_info (now_seg)->frchainP->frch_root;
+#else
+  f = frchain_now->frch_root;
+#endif
+#ifdef BFD_ASSEMBLER
   fix = seg_info (now_seg)->frchainP->fix_root;
+#else
+  fix = *seg_fix_rootP;
+#endif
   subseg_set (current_seg, current_subseg);
 
   /* Look through the frags of the section to find the code alignment.  */
@@ -150,8 +159,8 @@ eh_frame_code_alignment ()
 
   /* Skip the augmentation (a null terminated string).  */
 
+  iaug = 0;
   ++offset;
-  eh_state = 0;
   while (1)
     {
       while (f != NULL && offset >= f->fr_fix)
@@ -166,19 +175,10 @@ eh_frame_code_alignment ()
        }
       while (offset < f->fr_fix && f->fr_literal[offset] != '\0')
        {
-         switch (eh_state)
+         if ((size_t) iaug < (sizeof augmentation) - 1)
            {
-           case 0:
-             if (f->fr_literal[offset] == 'e')
-               eh_state = 1;
-             break;
-           case 1:
-             if (f->fr_literal[offset] == 'h')
-               eh_state = 2;
-             break;
-           default:
-             eh_state = 3;
-             break;
+             augmentation[iaug] = f->fr_literal[offset];
+             ++iaug;
            }
          ++offset;
        }
@@ -197,11 +197,15 @@ eh_frame_code_alignment ()
       return -1;
     }
 
-  /* If the augmentation field is "eh", then we have to skip a
-     pointer.  Unfortunately, we don't know how large it is.  We find
-     out by looking for a matching fixup.  */
-  if (eh_state == 2)
+  augmentation[iaug] = '\0';
+  if (augmentation[0] == '\0')
     {
+      /* No augmentation.  */
+    }
+  else if (strcmp (augmentation, "eh") == 0)
+    {
+      /* We have to skip a pointer.  Unfortunately, we don't know how
+        large it is.  We find out by looking for a matching fixup.  */
       while (fix != NULL
             && (fix->fx_frag != f || fix->fx_where != offset))
        fix = fix->fx_next;
@@ -220,6 +224,11 @@ eh_frame_code_alignment ()
          return -1;
        }
     }
+  else
+    {
+      code_alignment = -1;
+      return -1;
+    }
 
   /* We're now at the code alignment factor, which is a ULEB128.  If
      it isn't a single byte, forget it.  */
@@ -252,17 +261,52 @@ check_eh_frame (exp, pnbytes)
      expressionS *exp;
      unsigned int *pnbytes;
 {
+  static int saw_size;
+  static symbolS *size_end_sym;
   static int saw_advance_loc4;
   static fragS *loc4_frag;
   static int loc4_fix;
 
+  if (saw_size
+      && S_IS_DEFINED (size_end_sym))
+    {
+      /* We have come to the end of the CIE or FDE.  See below where
+         we set saw_size.  We must check this first because we may now
+         be looking at the next size.  */
+      saw_size = 0;
+      saw_advance_loc4 = 0;
+    }
+
   if (flag_traditional_format)
     {
       /* Don't optimize.  */
     }
   else if (strcmp (segment_name (now_seg), ".eh_frame") != 0)
-    saw_advance_loc4 = 0;
-  else if (*pnbytes == 1
+    {
+      saw_size = 0;
+      saw_advance_loc4 = 0;
+    }
+  else if (! saw_size
+          && *pnbytes == 4)
+    {
+      /* This might be the size of the CIE or FDE.  We want to know
+         the size so that we don't accidentally optimize across an FDE
+         boundary.  We recognize the size in one of two forms: a
+         symbol which will later be defined as a difference, or a
+         subtraction of two symbols.  Either way, we can tell when we
+         are at the end of the FDE because the symbol becomes defined
+         (in the case of a subtraction, the end symbol, from which the
+         start symbol is being subtracted).  Other ways of describing
+         the size will not be optimized.  */
+      if ((exp->X_op == O_symbol || exp->X_op == O_subtract)
+         && ! S_IS_DEFINED (exp->X_add_symbol))
+       {
+         saw_size = 1;
+         size_end_sym = exp->X_add_symbol;
+       }
+    }
+  else if (saw_size
+          && *pnbytes == 1
           && exp->X_op == O_constant
           && exp->X_add_number == DW_CFA_advance_loc4)
     {
This page took 0.043624 seconds and 4 git commands to generate.