This commit was generated by cvs2svn to track changes on a CVS vendor
[binutils-gdb.git] / gas / frags.c
index f52692e271d5e0556d9d4216c6eef127ab632989..240b2ee63a01f5671ac90d6cca308715a647791a 100644 (file)
@@ -1,6 +1,6 @@
 /* frags.c - manage frags -
-
-   Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 1998
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    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.  */
+   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.  */
 
 #include "as.h"
 #include "subsegs.h"
 #include "obstack.h"
 
-struct obstack frags;          /* All, and only, frags live here. */
-
 extern fragS zero_address_frag;
 extern fragS bss_address_frag;
 \f
@@ -33,7 +32,25 @@ frag_init ()
 {
   zero_address_frag.fr_type = rs_fill;
   bss_address_frag.fr_type = rs_fill;
-  obstack_begin (&frags, 5000);
+}
+\f
+/* Allocate a frag on the specified obstack.
+   Call this routine from everywhere else, so that all the weird alignment
+   hackery can be done in just one place.  */
+fragS *
+frag_alloc (ob)
+     struct obstack *ob;
+{
+  fragS *ptr;
+  int oalign;
+
+  (void) obstack_alloc (ob, 0);
+  oalign = obstack_alignment_mask (ob);
+  obstack_alignment_mask (ob) = 0;
+  ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG);
+  obstack_alignment_mask (ob) = oalign;
+  memset (ptr, 0, SIZEOF_STRUCT_FRAG);
+  return ptr;
 }
 \f
 /*
@@ -48,27 +65,25 @@ void
 frag_grow (nchars)
      unsigned int nchars;
 {
-  if (obstack_room (&frags) < nchars)
+  if (obstack_room (&frchain_now->frch_obstack) < nchars)
     {
-      unsigned int n, oldn;
+      unsigned int n;
       long oldc;
 
       frag_wane (frag_now);
       frag_new (0);
-      oldn = (unsigned) -1;
-      oldc = frags.chunk_size;
-      frags.chunk_size = 2 * nchars;
-      while ((n = obstack_room (&frags)) < nchars && n < oldn)
+      oldc = frchain_now->frch_obstack.chunk_size;
+      frchain_now->frch_obstack.chunk_size = 2 * nchars + SIZEOF_STRUCT_FRAG;
+      while ((n = obstack_room (&frchain_now->frch_obstack)) < nchars)
        {
          frag_wane (frag_now);
          frag_new (0);
-         oldn = n;
        }
-      frags.chunk_size = oldc;
+      frchain_now->frch_obstack.chunk_size = oldc;
     }
-  if (obstack_room (&frags) < nchars)
-    as_fatal ("Can't extend frag %d. chars", nchars);
-}                              /* frag_grow() */
+  if (obstack_room (&frchain_now->frch_obstack) < nchars)
+    as_fatal (_("Can't extend frag %d. chars"), nchars);
+}
 \f
 /*
  *                     frag_new()
@@ -89,36 +104,31 @@ frag_grow (nchars)
  */
 void 
 frag_new (old_frags_var_max_size)
-     int old_frags_var_max_size;/* Number of chars (already allocated on
-                                  obstack frags) */
-     /* in variable_length part of frag. */
+     /* Number of chars (already allocated on obstack frags) in
+       variable_length part of frag. */
+     int old_frags_var_max_size;
 {
-  register fragS *former_last_fragP;
-  register frchainS *frchP;
-  long tmp;
+  fragS *former_last_fragP;
+  frchainS *frchP;
+
+  assert (frchain_now->frch_last == frag_now);
 
+  /* Fix up old frag's fr_fix.  */
   frag_now->fr_fix = frag_now_fix () - old_frags_var_max_size;
-  /* Fix up old frag's fr_fix. */
+  /* Make sure its type is valid.  */
+  assert (frag_now->fr_type != 0);
 
-  obstack_finish (&frags);
   /* This will align the obstack so the next struct we allocate on it
      will begin at a correct boundary. */
+  obstack_finish (&frchain_now->frch_obstack);
   frchP = frchain_now;
   know (frchP);
   former_last_fragP = frchP->frch_last;
-  know (former_last_fragP);
-  know (former_last_fragP == frag_now);
-  obstack_blank (&frags, SIZEOF_STRUCT_FRAG);
-  /* We expect this will begin at a correct boundary for a struct. */
-  tmp = obstack_alignment_mask (&frags);
-  obstack_alignment_mask (&frags) = 0; /* Turn off alignment */
-  /* If we ever hit a machine where strings must be aligned, we Lose
-     Big.  */
-  frag_now = (fragS *) obstack_finish (&frags);
-  obstack_alignment_mask (&frags) = tmp;       /* Restore alignment */
-
-  /* Just in case we don't get zero'd bytes */
-  memset (frag_now, '\0', SIZEOF_STRUCT_FRAG);
+  assert (former_last_fragP != 0);
+  assert (former_last_fragP == frag_now);
+  frag_now = frag_alloc (&frchP->frch_obstack);
+
+  as_where (&frag_now->fr_file, &frag_now->fr_line);
 
   /* Generally, frag_now->points to an address rounded up to next
      alignment.  However, characters will add to obstack frags
@@ -134,6 +144,8 @@ frag_new (old_frags_var_max_size)
   }
 #endif
 
+  assert (frchain_now->frch_last == frag_now);
+
   frag_now->fr_next = NULL;
 }                              /* frag_new() */
 \f
@@ -153,15 +165,21 @@ frag_more (nchars)
 {
   register char *retval;
 
+  if (now_seg == absolute_section)
+    {
+      as_bad (_("attempt to allocate data in absolute section"));
+      subseg_set (text_section, 0);
+    }
+
   if (mri_common_symbol != NULL)
     {
-      as_bad ("attempt to allocate data in common section");
+      as_bad (_("attempt to allocate data in common section"));
       mri_common_symbol = NULL;
     }
 
   frag_grow (nchars);
-  retval = obstack_next_free (&frags);
-  obstack_blank_fast (&frags, nchars);
+  retval = obstack_next_free (&frchain_now->frch_obstack);
+  obstack_blank_fast (&frchain_now->frch_obstack, nchars);
   return (retval);
 }                              /* frag_more() */
 \f
@@ -183,23 +201,29 @@ frag_var (type, max_chars, var, subtype, symbol, offset, opcode)
      int var;
      relax_substateT subtype;
      symbolS *symbol;
-     long offset;
+     offsetT offset;
      char *opcode;
 {
   register char *retval;
 
   frag_grow (max_chars);
-  retval = obstack_next_free (&frags);
-  obstack_blank_fast (&frags, max_chars);
+  retval = obstack_next_free (&frchain_now->frch_obstack);
+  obstack_blank_fast (&frchain_now->frch_obstack, max_chars);
   frag_now->fr_var = var;
   frag_now->fr_type = type;
   frag_now->fr_subtype = subtype;
   frag_now->fr_symbol = symbol;
   frag_now->fr_offset = offset;
   frag_now->fr_opcode = opcode;
-  /* default these to zero. */
-  frag_now->fr_pcrel_adjust = 0;
-  frag_now->fr_bsr = 0;
+#ifdef USING_CGEN
+  frag_now->fr_cgen.insn = 0;
+  frag_now->fr_cgen.opindex = 0;
+  frag_now->fr_cgen.opinfo = 0;
+#endif
+#ifdef TC_FRAG_INIT
+  TC_FRAG_INIT (frag_now);
+#endif
+  as_where (&frag_now->fr_file, &frag_now->fr_line);
   frag_new (max_chars);
   return (retval);
 }
@@ -210,7 +234,6 @@ frag_var (type, max_chars, var, subtype, symbol, offset, opcode)
  * OVE: This variant of frag_var assumes that space for the tail has been
  *      allocated by caller.
  *      No call to frag_grow is done.
- *      Two new arguments have been added.
  */
 
 char *
@@ -220,20 +243,27 @@ frag_variant (type, max_chars, var, subtype, symbol, offset, opcode)
      int var;
      relax_substateT subtype;
      symbolS *symbol;
-     long offset;
+     offsetT offset;
      char *opcode;
 {
   register char *retval;
 
-  retval = obstack_next_free (&frags);
+  retval = obstack_next_free (&frchain_now->frch_obstack);
   frag_now->fr_var = var;
   frag_now->fr_type = type;
   frag_now->fr_subtype = subtype;
   frag_now->fr_symbol = symbol;
   frag_now->fr_offset = offset;
   frag_now->fr_opcode = opcode;
-  frag_now->fr_pcrel_adjust = 0;
-  frag_now->fr_bsr = 0;
+#ifdef USING_CGEN
+  frag_now->fr_cgen.insn = 0;
+  frag_now->fr_cgen.opindex = 0;
+  frag_now->fr_cgen.opinfo = 0;
+#endif
+#ifdef TC_FRAG_INIT
+  TC_FRAG_INIT (frag_now);
+#endif
+  as_where (&frag_now->fr_file, &frag_now->fr_line);
   frag_new (max_chars);
   return (retval);
 }                              /* frag_variant() */
@@ -252,55 +282,78 @@ frag_wane (fragP)
   fragP->fr_var = 0;
 }
 \f
-/*
- *                     frag_align()
- *
- * Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);".
- * Foo & bar are absolute integers.
- *
- * Call to close off the current frag with a ".align", then start a new
- * (so far empty) frag, in the same subsegment as the last frag.
- */
+/* Make an alignment frag.  The size of this frag will be adjusted to
+   force the next frag to have the appropriate alignment.  ALIGNMENT
+   is the power of two to which to align.  FILL_CHARACTER is the
+   character to use to fill in any bytes which are skipped.  MAX is
+   the maximum number of characters to skip when doing the alignment,
+   or 0 if there is no maximum.  */
 
 void 
-frag_align (alignment, fill_character)
+frag_align (alignment, fill_character, max)
      int alignment;
      int fill_character;
+     int max;
 {
-  char *p;
-  p = frag_var (rs_align, 1, 1, (relax_substateT) 0,
-               (symbolS *) 0, (long) alignment, (char *) 0);
-  *p = fill_character;
+  if (now_seg == absolute_section)
+    {
+      addressT new_off;
+
+      new_off = ((abs_section_offset + alignment - 1)
+                &~ ((1 << alignment) - 1));
+      if (max == 0 || new_off - abs_section_offset <= (addressT) max)
+       abs_section_offset = new_off;
+    }
+  else
+    {
+      char *p;
+
+      p = frag_var (rs_align, 1, 1, (relax_substateT) max,
+                   (symbolS *) 0, (offsetT) alignment, (char *) 0);
+      *p = fill_character;
+    }
 }
 
+/* Make an alignment frag like frag_align, but fill with a repeating
+   pattern rather than a single byte.  ALIGNMENT is the power of two
+   to which to align.  FILL_PATTERN is the fill pattern to repeat in
+   the bytes which are skipped.  N_FILL is the number of bytes in
+   FILL_PATTERN.  MAX is the maximum number of characters to skip when
+   doing the alignment, or 0 if there is no maximum.  */
+
 void 
-frag_align_pattern (alignment, fill_pattern, n_fill)
+frag_align_pattern (alignment, fill_pattern, n_fill, max)
      int alignment;
      const char *fill_pattern;
      int n_fill;
+     int max;
 {
   char *p;
-  p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) 0,
-               (symbolS *) 0, (long) alignment, (char *) 0);
+
+  p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) max,
+               (symbolS *) 0, (offsetT) alignment, (char *) 0);
   memcpy (p, fill_pattern, n_fill);
 }
 
-int
+addressT
 frag_now_fix ()
 {
-  return (char*)obstack_next_free (&frags) - frag_now->fr_literal;
+  if (now_seg == absolute_section)
+    return abs_section_offset;
+  return (addressT) ((char*) obstack_next_free (&frchain_now->frch_obstack)
+                    - frag_now->fr_literal);
 }
 
 void
 frag_append_1_char (datum)
      int datum;
 {
-  if (obstack_room (&frags) <= 1)
+  if (obstack_room (&frchain_now->frch_obstack) <= 1)
     {
       frag_wane (frag_now);
       frag_new (0);
     }
-  obstack_1grow (&frags, datum);
+  obstack_1grow (&frchain_now->frch_obstack, datum);
 }
 
 /* end of frags.c */