/* frags.c - manage frags -
-
- Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc.
+ Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+ 1999, 2000, 2001, 2003, 2004
+ 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, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, 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
/* Initialization for frag routines. */
+
void
-frag_init ()
+frag_init (void)
{
zero_address_frag.fr_type = rs_fill;
bss_address_frag.fr_type = rs_fill;
- obstack_begin (&frags, 5000);
}
\f
-/*
- * frag_grow()
- *
- * Try to augment current frag by nchars chars.
- * If there is no room, close of the current frag with a ".fill 0"
- * and begin a new frag. Unless the new frag has nchars chars available
- * do not return. Do not set up any fields of *now_frag.
- */
-void
-frag_grow (nchars)
- unsigned int nchars;
+/* Check that we're not trying to assemble into a section that can't
+ allocate frags (currently, this is only possible in the absolute
+ section), or into an mri common. */
+
+static void
+frag_alloc_check (const struct obstack *ob)
+{
+ if (ob->chunk_size == 0)
+ {
+ 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"));
+ mri_common_symbol = NULL;
+ }
+}
+
+/* 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 (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
+/* Try to augment current frag by nchars chars.
+ If there is no room, close of the current frag with a ".fill 0"
+ and begin a new frag. Unless the new frag has nchars chars available
+ do not return. Do not set up any fields of *now_frag. */
+
+void
+frag_grow (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)
- {
- frag_wane (frag_now);
- frag_new (0);
- oldn = n;
- }
- frags.chunk_size = oldc;
+ oldc = frchain_now->frch_obstack.chunk_size;
+ /* Try to allocate a bit more than needed right now. But don't do
+ this if we would waste too much memory. Especially necessary
+ for extremely big (like 2GB initialized) frags. */
+ if (nchars < 0x10000)
+ frchain_now->frch_obstack.chunk_size = 2 * nchars;
+ else
+ frchain_now->frch_obstack.chunk_size = nchars + 0x10000;
+ frchain_now->frch_obstack.chunk_size += SIZEOF_STRUCT_FRAG;
+ if (frchain_now->frch_obstack.chunk_size > 0)
+ while ((n = obstack_room (&frchain_now->frch_obstack)) < nchars
+ && (unsigned long) frchain_now->frch_obstack.chunk_size > nchars)
+ {
+ frag_wane (frag_now);
+ frag_new (0);
+ }
+ 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 %u chars"), nchars);
+}
\f
-/*
- * frag_new()
- *
- * Call this to close off a completed frag, and start up a new (empty)
- * frag, in the same subsegment as the old frag.
- * [frchain_now remains the same but frag_now is updated.]
- * Because this calculates the correct value of fr_fix by
- * looking at the obstack 'frags', it needs to know how many
- * characters at the end of the old frag belong to (the maximal)
- * fr_var: the rest must belong to fr_fix.
- * It doesn't actually set up the old frag's fr_var: you may have
- * set fr_var == 1, but allocated 10 chars to the end of the frag:
- * in this case you pass old_frags_var_max_size == 10.
- *
- * Make a new frag, initialising some components. Link new frag at end
- * of frchain_now.
- */
-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. */
+/* Call this to close off a completed frag, and start up a new (empty)
+ frag, in the same subsegment as the old frag.
+ [frchain_now remains the same but frag_now is updated.]
+ Because this calculates the correct value of fr_fix by
+ looking at the obstack 'frags', it needs to know how many
+ characters at the end of the old frag belong to the maximal
+ variable part; The rest must belong to fr_fix.
+ It doesn't actually set up the old frag's fr_var. You may have
+ set fr_var == 1, but allocated 10 chars to the end of the frag;
+ In this case you pass old_frags_var_max_size == 10.
+ In fact, you may use fr_var for something totally unrelated to the
+ size of the variable part of the frag; None of the generic frag
+ handling code makes use of fr_var.
+
+ Make a new frag, initialising some components. Link new frag at end
+ of frchain_now. */
+
+void
+frag_new (int old_frags_var_max_size
+ /* Number of chars (already allocated on obstack frags) in
+ variable_length part of frag. */)
{
- register fragS *former_last_fragP;
- register frchainS *frchP;
- long tmp;
+ fragS *former_last_fragP;
+ frchainS *frchP;
+
+ assert (frchain_now->frch_last == frag_now);
- frag_now->fr_fix = frag_now_fix () - old_frags_var_max_size;
- /* Fix up old frag's fr_fix. */
+ /* Fix up old frag's fr_fix. */
+ frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size;
+ /* 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. */
+ 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
IMMEDIATELY after the struct frag, even if they are not starting
- at an alignment address. */
+ at an alignment address. */
former_last_fragP->fr_next = frag_now;
frchP->frch_last = frag_now;
}
#endif
+ assert (frchain_now->frch_last == frag_now);
+
frag_now->fr_next = NULL;
-} /* frag_new() */
+}
\f
-/*
- * frag_more()
- *
- * Start a new frag unless we have n more chars of room in the current frag.
- * Close off the old frag with a .fill 0.
- *
- * Return the address of the 1st char to write into. Advance
- * frag_now_growth past the new chars.
- */
+/* Start a new frag unless we have n more chars of room in the current frag.
+ Close off the old frag with a .fill 0.
+
+ Return the address of the 1st char to write into. Advance
+ frag_now_growth past the new chars. */
char *
-frag_more (nchars)
- int nchars;
+frag_more (int 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");
- mri_common_symbol = NULL;
- }
-
+ frag_alloc_check (&frchain_now->frch_obstack);
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
-/*
- * frag_var()
- *
- * Start a new frag unless we have max_chars more chars of room in the current frag.
- * Close off the old frag with a .fill 0.
- *
- * Set up a machine_dependent relaxable frag, then start a new frag.
- * Return the address of the 1st char of the var part of the old frag
- * to write into.
- */
+/* Start a new frag unless we have max_chars more chars of room in the
+ current frag. Close off the old frag with a .fill 0.
+
+ Set up a machine_dependent relaxable frag, then start a new frag.
+ Return the address of the 1st char of the var part of the old frag
+ to write into. */
char *
-frag_var (type, max_chars, var, subtype, symbol, offset, opcode)
- relax_stateT type;
- int max_chars;
- int var;
- relax_substateT subtype;
- symbolS *symbol;
- long offset;
- char *opcode;
+frag_var (relax_stateT type, int max_chars, int var, relax_substateT subtype,
+ symbolS *symbol, 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);
}
\f
-/*
- * frag_variant()
- *
- * 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.
- */
+/* OVE: This variant of frag_var assumes that space for the tail has been
+ allocated by caller.
+ No call to frag_grow is done. */
char *
-frag_variant (type, max_chars, var, subtype, symbol, offset, opcode)
- relax_stateT type;
- int max_chars;
- int var;
- relax_substateT subtype;
- symbolS *symbol;
- long offset;
- char *opcode;
+frag_variant (relax_stateT type, int max_chars, int var,
+ relax_substateT subtype, symbolS *symbol, 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() */
+}
\f
-/*
- * frag_wane()
- *
- * Reduce the variable end of a frag to a harmless state.
- */
-void
-frag_wane (fragP)
- register fragS *fragP;
+/* Reduce the variable end of a frag to a harmless state. */
+
+void
+frag_wane (register fragS *fragP)
{
fragP->fr_type = rs_fill;
fragP->fr_offset = 0;
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.
- */
-
-void
-frag_align (alignment, fill_character)
- int alignment;
- int fill_character;
+/* Return the number of bytes by which the current frag can be grown. */
+
+int
+frag_room (void)
{
- char *p;
- p = frag_var (rs_align, 1, 1, (relax_substateT) 0,
- (symbolS *) 0, (long) alignment, (char *) 0);
- *p = fill_character;
+ return obstack_room (&frchain_now->frch_obstack);
+}
+\f
+/* 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 (int alignment, int fill_character, int max)
+{
+ if (now_seg == absolute_section)
+ {
+ addressT new_off;
+ addressT mask;
+
+ mask = (~(addressT) 0) << alignment;
+ new_off = (abs_section_offset + ~mask) & mask;
+ 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;
+ }
}
-void
-frag_align_pattern (alignment, fill_pattern, n_fill)
- int alignment;
- const char *fill_pattern;
- int n_fill;
+/* 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 (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
-frag_now_fix ()
+/* The NOP_OPCODE is for the alignment fill value. Fill it with a nop
+ instruction so that the disassembler does not choke on it. */
+#ifndef NOP_OPCODE
+#define NOP_OPCODE 0x00
+#endif
+
+/* Use this to restrict the amount of memory allocated for representing
+ the alignment code. Needs to be large enough to hold any fixed sized
+ prologue plus the replicating portion. */
+#ifndef MAX_MEM_FOR_RS_ALIGN_CODE
+ /* Assume that if HANDLE_ALIGN is not defined then no special action
+ is required to code fill, which means that we get just repeat the
+ one NOP_OPCODE byte. */
+# ifndef HANDLE_ALIGN
+# define MAX_MEM_FOR_RS_ALIGN_CODE 1
+# else
+# define MAX_MEM_FOR_RS_ALIGN_CODE ((1 << alignment) - 1)
+# endif
+#endif
+
+void
+frag_align_code (int alignment, int max)
+{
+ char *p;
+
+ p = frag_var (rs_align_code, MAX_MEM_FOR_RS_ALIGN_CODE, 1,
+ (relax_substateT) max, (symbolS *) 0,
+ (offsetT) alignment, (char *) 0);
+ *p = NOP_OPCODE;
+}
+
+addressT
+frag_now_fix_octets (void)
{
if (now_seg == absolute_section)
return abs_section_offset;
- return (char*)obstack_next_free (&frags) - frag_now->fr_literal;
+
+ return ((char *) obstack_next_free (&frchain_now->frch_obstack)
+ - frag_now->fr_literal);
+}
+
+addressT
+frag_now_fix (void)
+{
+ return frag_now_fix_octets () / OCTETS_PER_BYTE;
}
void
-frag_append_1_char (datum)
- int datum;
+frag_append_1_char (int datum)
{
- if (obstack_room (&frags) <= 1)
+ frag_alloc_check (&frchain_now->frch_obstack);
+ 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 */