/* frags.c - manage frags -
- Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
#include "obstack.h"
extern fragS zero_address_frag;
-extern fragS bss_address_frag;
+extern fragS predefined_address_frag;
+
+static int totalfrags;
+
+int
+get_frag_count (void)
+{
+ return totalfrags;
+}
+
+void
+clear_frag_count (void)
+{
+ totalfrags = 0;
+}
\f
/* Initialization for frag routines. */
frag_init (void)
{
zero_address_frag.fr_type = rs_fill;
- bss_address_frag.fr_type = rs_fill;
+ predefined_address_frag.fr_type = rs_fill;
}
\f
/* Check that we're not trying to assemble into a section that can't
ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG);
obstack_alignment_mask (ob) = oalign;
memset (ptr, 0, SIZEOF_STRUCT_FRAG);
+ totalfrags++;
return ptr;
}
\f
do not return. Do not set up any fields of *now_frag. */
void
-frag_grow (unsigned int nchars)
+frag_grow (size_t nchars)
{
if (obstack_room (&frchain_now->frch_obstack) < nchars)
{
- unsigned int n;
- long oldc;
-
- frag_wane (frag_now);
- frag_new (0);
- oldc = frchain_now->frch_obstack.chunk_size;
- frchain_now->frch_obstack.chunk_size = 2 * nchars + 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;
+ size_t oldc;
+ size_t newc;
+
+ /* 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)
+ newc = 2 * nchars;
+ else
+ newc = nchars + 0x10000;
+ newc += SIZEOF_STRUCT_FRAG;
+
+ /* Check for possible overflow. */
+ if (newc < nchars)
+ as_fatal (ngettext ("can't extend frag %lu char",
+ "can't extend frag %lu chars",
+ (unsigned long) nchars),
+ (unsigned long) nchars);
+
+ /* Force to allocate at least NEWC bytes, but not less than the
+ default. */
+ oldc = obstack_chunk_size (&frchain_now->frch_obstack);
+ if (newc > oldc)
+ obstack_chunk_size (&frchain_now->frch_obstack) = newc;
+
+ while (obstack_room (&frchain_now->frch_obstack) < nchars)
+ {
+ /* Not enough room in this frag. Close it and start a new one.
+ This must be done in a loop because the created frag may not
+ be big enough if the current obstack chunk is used. */
+ frag_wane (frag_now);
+ frag_new (0);
+ }
+
+ /* Restore the old chunk size. */
+ obstack_chunk_size (&frchain_now->frch_obstack) = oldc;
}
- if (obstack_room (&frchain_now->frch_obstack) < nchars)
- as_fatal (_("can't extend frag %u chars"), nchars);
}
\f
/* Call this to close off a completed frag, and start up a new (empty)
of frchain_now. */
void
-frag_new (int old_frags_var_max_size
+frag_new (size_t old_frags_var_max_size
/* Number of chars (already allocated on obstack frags) in
variable_length part of frag. */)
{
fragS *former_last_fragP;
frchainS *frchP;
- assert (frchain_now->frch_last == frag_now);
+ gas_assert (frchain_now->frch_last == frag_now);
/* Fix up old frag's fr_fix. */
- frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size;
+ frag_now->fr_fix = frag_now_fix_octets ();
+ gas_assert (frag_now->fr_fix >= old_frags_var_max_size);
+ frag_now->fr_fix -= old_frags_var_max_size;
/* Make sure its type is valid. */
- assert (frag_now->fr_type != 0);
+ gas_assert (frag_now->fr_type != 0);
/* This will align the obstack so the next struct we allocate on it
will begin at a correct boundary. */
frchP = frchain_now;
know (frchP);
former_last_fragP = frchP->frch_last;
- assert (former_last_fragP != 0);
- assert (former_last_fragP == frag_now);
+ gas_assert (former_last_fragP != 0);
+ gas_assert (former_last_fragP == frag_now);
frag_now = frag_alloc (&frchP->frch_obstack);
- as_where (&frag_now->fr_file, &frag_now->fr_line);
+ frag_now->fr_file = as_where (&frag_now->fr_line);
/* Generally, frag_now->points to an address rounded up to next
alignment. However, characters will add to obstack frags
}
#endif
- assert (frchain_now->frch_last == frag_now);
+ gas_assert (frchain_now->frch_last == frag_now);
frag_now->fr_next = NULL;
}
frag_now_growth past the new chars. */
char *
-frag_more (int nchars)
+frag_more (size_t nchars)
{
- register char *retval;
+ char *retval;
frag_alloc_check (&frchain_now->frch_obstack);
frag_grow (nchars);
retval = obstack_next_free (&frchain_now->frch_obstack);
obstack_blank_fast (&frchain_now->frch_obstack, nchars);
- return (retval);
+ return retval;
}
\f
-/* 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.
+/* Close the current frag, setting its fields for a relaxable frag. Start a
+ new frag. */
- 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 (relax_stateT type, int max_chars, int var, relax_substateT subtype,
- symbolS *symbol, offsetT offset, char *opcode)
+static void
+frag_var_init (relax_stateT type, size_t max_chars, size_t var,
+ relax_substateT subtype, symbolS *symbol, offsetT offset,
+ char *opcode)
{
- register char *retval;
-
- frag_grow (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_cgen.opinfo = 0;
#endif
#ifdef TC_FRAG_INIT
- TC_FRAG_INIT (frag_now);
+ TC_FRAG_INIT (frag_now, max_chars);
#endif
- as_where (&frag_now->fr_file, &frag_now->fr_line);
+ frag_now->fr_file = as_where (&frag_now->fr_line);
+
frag_new (max_chars);
- return (retval);
+}
+
+/* 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 (relax_stateT type, size_t max_chars, size_t var,
+ relax_substateT subtype, symbolS *symbol, offsetT offset,
+ char *opcode)
+{
+ char *retval;
+
+ frag_grow (max_chars);
+ retval = obstack_next_free (&frchain_now->frch_obstack);
+ obstack_blank_fast (&frchain_now->frch_obstack, max_chars);
+ frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode);
+ return retval;
}
\f
/* OVE: This variant of frag_var assumes that space for the tail has been
No call to frag_grow is done. */
char *
-frag_variant (relax_stateT type, int max_chars, int var,
+frag_variant (relax_stateT type, size_t max_chars, size_t var,
relax_substateT subtype, symbolS *symbol, offsetT offset,
char *opcode)
{
- register char *retval;
+ char *retval;
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;
-#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_var_init (type, max_chars, var, subtype, symbol, offset, opcode);
+
+ return retval;
}
\f
/* Reduce the variable end of a frag to a harmless state. */
void
-frag_wane (register fragS *fragP)
+frag_wane (fragS *fragP)
{
fragP->fr_type = rs_fill;
fragP->fr_offset = 0;
\f
/* Return the number of bytes by which the current frag can be grown. */
-int
+size_t
frag_room (void)
{
return obstack_room (&frchain_now->frch_obstack);
void
frag_align_pattern (int alignment, const char *fill_pattern,
- int n_fill, int max)
+ size_t n_fill, int max)
{
char *p;
}
obstack_1grow (&frchain_now->frch_obstack, datum);
}
+
+/* Return TRUE if FRAG1 and FRAG2 have a fixed relationship between
+ their start addresses. Set OFFSET to the difference in address
+ not already accounted for in the frag FR_ADDRESS. */
+
+bfd_boolean
+frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset)
+{
+ const fragS *frag;
+ offsetT off;
+
+ /* Start with offset initialised to difference between the two frags.
+ Prior to assigning frag addresses this will be zero. */
+ off = frag1->fr_address - frag2->fr_address;
+ if (frag1 == frag2)
+ {
+ *offset = off;
+ return TRUE;
+ }
+
+ /* Maybe frag2 is after frag1. */
+ frag = frag1;
+ while (frag->fr_type == rs_fill)
+ {
+ off += frag->fr_fix + frag->fr_offset * frag->fr_var;
+ frag = frag->fr_next;
+ if (frag == NULL)
+ break;
+ if (frag == frag2)
+ {
+ *offset = off;
+ return TRUE;
+ }
+ }
+
+ /* Maybe frag1 is after frag2. */
+ off = frag1->fr_address - frag2->fr_address;
+ frag = frag2;
+ while (frag->fr_type == rs_fill)
+ {
+ off -= frag->fr_fix + frag->fr_offset * frag->fr_var;
+ frag = frag->fr_next;
+ if (frag == NULL)
+ break;
+ if (frag == frag1)
+ {
+ *offset = off;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/* Return TRUE if we can determine whether FRAG2 OFF2 appears after
+ (strict >, not >=) FRAG1 OFF1, assuming it is not before. Set
+ *OFFSET so that resolve_expression will resolve an O_gt operation
+ between them to false (0) if they are guaranteed to be at the same
+ location, or to true (-1) if they are guaranteed to be at different
+ locations. Return FALSE conservatively, e.g. if neither result can
+ be guaranteed (yet).
+
+ They are known to be in the same segment, and not the same frag
+ (this is a fallback for frag_offset_fixed_p, that always takes care
+ of this case), and it is expected (from the uses this is designed
+ to simplify, namely location view increments) that frag2 is
+ reachable from frag1 following the fr_next links, rather than the
+ other way round. */
+
+bfd_boolean
+frag_gtoffset_p (valueT off2, const fragS *frag2,
+ valueT off1, const fragS *frag1, offsetT *offset)
+{
+ /* Insanity check. */
+ if (frag2 == frag1 || off1 > frag1->fr_fix)
+ return FALSE;
+
+ /* If the first symbol offset is at the end of the first frag and
+ the second symbol offset at the beginning of the second frag then
+ it is possible they are at the same address. Go looking for a
+ non-zero fr_fix in any frag between these frags. If found then
+ we can say the O_gt result will be true. If no such frag is
+ found we assume that frag1 or any of the following frags might
+ have a variable tail and thus the answer is unknown. This isn't
+ strictly true; some frags don't have a variable tail, but it
+ doesn't seem worth optimizing for those cases. */
+ const fragS *frag = frag1;
+ offsetT delta = off2 - off1;
+ for (;;)
+ {
+ delta += frag->fr_fix;
+ frag = frag->fr_next;
+ if (frag == frag2)
+ {
+ if (delta == 0)
+ return FALSE;
+ break;
+ }
+ /* If we run off the end of the frag chain then we have a case
+ where frag2 is not after frag1, ie. an O_gt expression not
+ created for .loc view. */
+ if (frag == NULL)
+ return FALSE;
+ }
+
+ *offset = (off2 - off1 - delta) * OCTETS_PER_BYTE;
+ return TRUE;
+}