[PATCH] gas: Fix comment on definition of frag_grow()
[deliverable/binutils-gdb.git] / gas / frags.c
index 3f4663cf3f61084680ea712b80c3a7d14e2913fb..c926ec3ba1ea5a92ca9966306c889ee27d95ea80 100644 (file)
 /* frags.c - manage frags -
-   Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
-   
+   Copyright (C) 1987-2020 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,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    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, 675 Mass Ave, Cambridge, MA 02139, 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. */
-
-fragS zero_address_frag = {
-       0,                      /* fr_address */
-       NULL,                   /* fr_next */
-       0,                      /* fr_fix */
-       0,                      /* fr_var */
-       0,                      /* fr_symbol */
-       0,                      /* fr_offset */
-       NULL,                   /* fr_opcode */
-       rs_fill,                /* fr_type */
-       0,                      /* fr_subtype */
-       0,                      /* fr_pcrel_adjust */
-       0,                      /* fr_bsr */
-       0                       /* fr_literal [0] */
-    };
-
-fragS bss_address_frag = {
-       0,                      /* fr_address. Gets filled in to make up
-                                  sy_value-s. */
-       NULL,                   /* fr_next */
-       0,                      /* fr_fix */
-       0,                      /* fr_var */
-       0,                      /* fr_symbol */
-       0,                      /* fr_offset */
-       NULL,                   /* fr_opcode */
-       rs_fill,                /* fr_type */
-       0,                      /* fr_subtype */
-       0,                      /* fr_pcrel_adjust */
-       0,                      /* fr_bsr */
-       0                       /* fr_literal [0] */
-    };
+extern fragS zero_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
-/*
- *                     frag_grow()
- *
- * Internal.
- * 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.
- */
-static void frag_grow(nchars)
-unsigned int nchars;
+/* Initialization for frag routines.  */
+
+void
+frag_init (void)
 {
-       if (obstack_room (&frags) < nchars) {
-               unsigned int n,oldn;
-               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;
-       }
-       if (obstack_room (&frags) < nchars)
-           as_fatal("Can't extend frag %d. chars", nchars);
-} /* frag_grow() */
+  zero_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
+   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);
+  totalfrags++;
+  return ptr;
+}
 \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. */
+/* Try to augment current frag by nchars chars.
+   If there is no room, close off the current frag with a ".fill 0"
+   and begin a new frag.  Then loop until the new frag has at least
+   nchars chars available.  Does not set up any fields in frag_now.  */
+
+void
+frag_grow (size_t nchars)
 {
-       register    fragS * former_last_fragP;
-       /*    char   *throw_away_pointer; JF unused */
-       register    frchainS * frchP;
-       long    tmp;            /* JF */
-       
-       frag_now->fr_fix = (char *) (obstack_next_free (&frags)) -
-           (frag_now->fr_literal) - old_frags_var_max_size;
-       /* Fix up old frag's fr_fix. */
-       
-       obstack_finish (&frags);
-       /* 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;
-       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 */
-       bzero(frag_now, SIZEOF_STRUCT_FRAG);
-       
-       /*    obstack_unaligned_done (&frags, &frag_now); */
-       /*    know (frags.obstack_c_next_free == frag_now->fr_literal); */
-       /* 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. */
-       former_last_fragP->fr_next = frag_now;
-       frchP->frch_last = frag_now;
-       
+  if (obstack_room (&frchain_now->frch_obstack) < nchars)
+    {
+      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;
+    }
+}
+\f
+/* 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 (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;
+
+  gas_assert (frchain_now->frch_last == frag_now);
+
+  /* Fix up old frag's fr_fix.  */
+  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.  */
+  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.  */
+  obstack_finish (&frchain_now->frch_obstack);
+  frchP = frchain_now;
+  know (frchP);
+  former_last_fragP = frchP->frch_last;
+  gas_assert (former_last_fragP != 0);
+  gas_assert (former_last_fragP == frag_now);
+  frag_now = frag_alloc (&frchP->frch_obstack);
+
+  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
+     IMMEDIATELY after the struct frag, even if they are not starting
+     at an alignment address.  */
+  former_last_fragP->fr_next = frag_now;
+  frchP->frch_last = frag_now;
+
 #ifndef NO_LISTING
-       {
-               extern struct list_info_struct *listing_tail;
-               frag_now->line = listing_tail;
-       }
+  {
+    extern struct list_info_struct *listing_tail;
+    frag_now->line = listing_tail;
+  }
 #endif
-       
-       frag_now->fr_next = NULL;
-}                              /* frag_new() */
+
+  gas_assert (frchain_now->frch_last == frag_now);
+
+  frag_now->fr_next = NULL;
+}
 \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.
- */
-
-char *frag_more (nchars)
-int nchars;
+/* 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 (size_t nchars)
 {
-       register char  *retval;
-       
-       frag_grow (nchars);
-       retval = obstack_next_free (&frags);
-       obstack_blank_fast (&frags, nchars);
-       return (retval);
-}                              /* frag_more() */
+  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;
+}
 \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.
- */
-
-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;
+/* Close the current frag, setting its fields for a relaxable frag.  Start a
+   new frag.  */
+
+static void
+frag_var_init (relax_stateT type, size_t max_chars, size_t var,
+              relax_substateT subtype, symbolS *symbol, offsetT offset,
+               char *opcode)
+{
+  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, max_chars);
+#endif
+  frag_now->fr_file = as_where (&frag_now->fr_line);
+
+  frag_new (max_chars);
+}
+
+/* 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)
 {
-       register char  *retval;
-       
-       frag_grow (max_chars);
-       retval = obstack_next_free (&frags);
-       obstack_blank_fast (&frags, 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;
-       frag_new (max_chars);
-       return (retval);
-}                              /* frag_var() */
+  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
-/*
- *                     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.
- */
-
-char *frag_variant(type, max_chars, var, subtype, symbol, offset, opcode, pcrel_adjust,bsr)
-relax_stateT    type;
-int             max_chars;
-int             var;
-relax_substateT         subtype;
-symbolS                *symbol;
-long            offset;
-char           *opcode;
-int             pcrel_adjust;
-char            bsr;
+/* 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 (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 (&frags);
-       /*  obstack_blank_fast (&frags, max_chars); */ /* OVE: so far the only diff */
-       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 = pcrel_adjust;
-       frag_now->fr_bsr = bsr;
-       frag_new (max_chars);
-       return (retval);
-}                              /* frag_variant() */
+  char *retval;
+
+  retval = obstack_next_free (&frchain_now->frch_obstack);
+  frag_var_init (type, max_chars, var, subtype, symbol, offset, opcode);
+
+  return retval;
+}
 \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 (fragS *fragP)
 {
-       fragP->fr_type = rs_fill;
-       fragP->fr_offset = 0;
-       fragP->fr_var = 0;
+  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.  */
+
+size_t
+frag_room (void)
+{
+  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;
+    }
+}
+
+/* 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,
+                   size_t n_fill, int max)
+{
+  char *p;
+
+  p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) max,
+               (symbolS *) 0, (offsetT) alignment, (char *) 0);
+  memcpy (p, fill_pattern, n_fill);
+}
+
+/* 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 (&frchain_now->frch_obstack)
+         - frag_now->fr_literal);
+}
+
+addressT
+frag_now_fix (void)
 {
-       *(frag_var (rs_align, 1, 1, (relax_substateT)0, (symbolS *)0,
-                   (long)alignment, (char *)0)) = fill_character;
-} /* frag_align() */
+  /* Symbols whose section has SEC_ELF_OCTETS set,
+     resolve to octets instead of target bytes.  */
+  if (now_seg->flags & SEC_OCTETS)
+    return frag_now_fix_octets ();
+  else
+    return frag_now_fix_octets () / OCTETS_PER_BYTE;
+}
 
-/* end: frags.c */
+void
+frag_append_1_char (int datum)
+{
+  frag_alloc_check (&frchain_now->frch_obstack);
+  if (obstack_room (&frchain_now->frch_obstack) <= 1)
+    {
+      frag_wane (frag_now);
+      frag_new (0);
+    }
+  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;
+}
This page took 0.031661 seconds and 4 git commands to generate.