Don't abort for invalid input, print an error message instead.
[deliverable/binutils-gdb.git] / gas / subsegs.c
index 5ce2e9e33dba800edf130043527344d3df18b116..1d29bbaf2b38cd8ff6185f3f13e030e523004839 100644 (file)
@@ -1,5 +1,5 @@
 /* subsegs.c - subsegments -
-   Copyright (C) 1987, 1990, 1991, 1992, 1993, 1994
+   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
    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, 675 Mass Ave, Cambridge, MA 02139, 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.  */
 
-/*
- * Segments & sub-segments.
- */
+/* Segments & sub-segments.  */
 
 #include "as.h"
 
 
 frchainS *frchain_root, *frchain_now;
 
+static struct obstack frchains;
+
 #ifndef BFD_ASSEMBLER
 #ifdef MANY_SEGMENTS
 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
 
 #else
-/* Commented in "subsegs.h". */
+/* Commented in "subsegs.h".  */
 frchainS *data0_frchainP, *bss0_frchainP;
 
 #endif /* MANY_SEGMENTS */
-char *const seg_name[] =
-{
+char const *const seg_name[] = {
   "absolute",
 #ifdef MANY_SEGMENTS
   "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9",
+  "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19",
+  "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29",
+  "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39",
 #else
   "text",
   "data",
@@ -56,7 +59,7 @@ char *const seg_name[] =
   "transfert vector postload",
   "register",
   "",
-};                             /* Used by error reporters, dumpers etc. */
+};                             /* Used by error reporters, dumpers etc.  */
 #else /* BFD_ASSEMBLER */
 
 /* Gas segment information for bfd_abs_section_ptr and
@@ -67,6 +70,10 @@ static segment_info_type *und_seg_info;
 #endif /* BFD_ASSEMBLER */
 
 static void subseg_set_rest PARAMS ((segT, subsegT));
+
+static fragS dummy_frag;
+
+static frchainS absolute_frchain;
 \f
 void
 subsegs_begin ()
@@ -87,18 +94,18 @@ subsegs_begin ()
   know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
 #endif
 
-  obstack_begin (&frags, 5000);
+  obstack_begin (&frchains, chunksize);
+#if __GNUC__ >= 2
+  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
+#endif
+
   frchain_root = NULL;
-  frchain_now = NULL;          /* Warn new_subseg() that we are booting. */
-  /* Fake up 1st frag.  It won't be used=> is ok if obstack...
-     pads the end of it for alignment. */
-  frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG);
-  memset (frag_now, 0, SIZEOF_STRUCT_FRAG);
+  frchain_now = NULL;          /* Warn new_subseg() that we are booting.  */
+
+  frag_now = &dummy_frag;
 
 #ifndef BFD_ASSEMBLER
-  /* This 1st frag will not be in any frchain.
-     We simply give subseg_new somewhere to scribble. */
-  now_subseg = 42;             /* Lie for 1st call to subseg_new. */
+  now_subseg = 42;             /* Lie for 1st call to subseg_new.  */
 #ifdef MANY_SEGMENTS
   {
     int i;
@@ -118,6 +125,13 @@ subsegs_begin ()
 #endif /* ! MANY_SEGMENTS */
 #endif /* ! BFD_ASSEMBLER */
 
+  absolute_frchain.frch_seg = absolute_section;
+  absolute_frchain.frch_subseg = 0;
+#ifdef BFD_ASSEMBLER
+  absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
+#endif
+  absolute_frchain.frch_frag_now = &zero_address_frag;
+  absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
 }
 \f
 /*
@@ -138,6 +152,9 @@ subseg_change (seg, subseg)
   now_seg = seg;
   now_subseg = subseg;
 
+  if (now_seg == absolute_section)
+    return;
+
 #ifdef BFD_ASSEMBLER
   {
     segment_info_type *seginfo;
@@ -189,33 +206,33 @@ subseg_set_rest (seg, subseg)
      segT seg;
      subsegT subseg;
 {
-  long tmp;                    /* JF for obstack alignment hacking */
   register frchainS *frcP;     /* crawl frchain chain */
   register frchainS **lastPP;  /* address of last pointer */
   frchainS *newP;              /* address of new frchain */
-  register fragS *former_last_fragP;
-  register fragS *new_fragP;
 
-  if (frag_now)                /* If not bootstrapping. */
+  mri_common_symbol = NULL;
+
+  if (frag_now && frchain_now)
+    frchain_now->frch_frag_now = frag_now;
+
+  assert (frchain_now == 0
+         || now_seg == undefined_section
+         || now_seg == absolute_section
+         || frchain_now->frch_last == frag_now);
+
+  subseg_change (seg, (int) subseg);
+
+  if (seg == absolute_section)
     {
-      frag_now->fr_fix = (char*) obstack_next_free (&frags) - frag_now->fr_literal;
-      frag_wane (frag_now);    /* Close off any frag in old subseg. */
+      frchain_now = &absolute_frchain;
+      frag_now = &zero_address_frag;
+      return;
     }
-  /*
-   * It would be nice to keep an obstack for each subsegment, if we swap
-   * subsegments a lot. Hence we would have much fewer frag_wanes().
-   */
-  {
-    obstack_finish (&frags);
-    /*
-     * If we don't do the above, the next object we put on obstack frags
-     * will appear to start at the fr_literal of the current frag.
-     * Also, above ensures that the next object will begin on a
-     * address that is aligned correctly for the engine that runs
-     * this program.
-     */
-  }
-  subseg_change (seg, (int) subseg);
+
+  assert (frchain_now == 0
+         || now_seg == undefined_section
+         || frchain_now->frch_last == frag_now);
+
   /*
    * Attempt to find or make a frchain for that sub seg.
    * Crawl along chain of frchainSs, begins @ frchain_root.
@@ -255,59 +272,48 @@ subseg_set_rest (seg, subseg)
    */
   if (!frcP
       || (frcP->frch_seg > seg
-         || frcP->frch_subseg > subseg))       /* Kinky logic only works with 2 segments. */
+         || frcP->frch_subseg > subseg))       /* Kinky logic only works with 2 segments.  */
     {
       /*
        * This should be the only code that creates a frchainS.
        */
-      newP = (frchainS *) obstack_alloc (&frags, sizeof (frchainS));
-      memset (newP, 0, sizeof (frchainS));
-      /* This begines on a good boundary because a obstack_done()
-        preceeded it.  It implies an obstack_done(), so we expect
-        the next object allocated to begin on a correct boundary. */
-      *lastPP = newP;
-      newP->frch_next = frcP;  /* perhaps NULL */
-      (frcP = newP)->frch_subseg = subseg;
+      newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
+      newP->frch_subseg = subseg;
       newP->frch_seg = seg;
-      newP->frch_last = NULL;
 #ifdef BFD_ASSEMBLER
       newP->fix_root = NULL;
       newP->fix_tail = NULL;
 #endif
+      obstack_begin (&newP->frch_obstack, chunksize);
+#if __GNUC__ >= 2
+      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
+#endif
+      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
+      newP->frch_frag_now->fr_type = rs_fill;
+
+      newP->frch_root = newP->frch_last = newP->frch_frag_now;
+
+      *lastPP = newP;
+      newP->frch_next = frcP;  /* perhaps NULL */
+
+#ifdef BFD_ASSEMBLER
+      {
+       segment_info_type *seginfo;
+       seginfo = seg_info (seg);
+       if (seginfo && seginfo->frchainP == frcP)
+         seginfo->frchainP = newP;
+      }
+#endif
+
+      frcP = newP;
     }
   /*
-   * Here with frcP ->ing to the frchainS for subseg.
+   * Here with frcP pointing to the frchainS for subseg.
    */
   frchain_now = frcP;
-  /*
-   * Make a fresh frag for the subsegment.
-   */
-  /* We expect this to happen on a correct boundary since it was
-     proceeded by a obstack_done(). */
-  tmp = obstack_alignment_mask (&frags);       /* JF disable alignment */
-  obstack_alignment_mask (&frags) = 0;
-  frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG);
-  memset (frag_now, 0, SIZEOF_STRUCT_FRAG);
-  obstack_alignment_mask (&frags) = tmp;
-  /* But we want any more chars to come immediately after the
-     structure we just made. */
-  new_fragP = frag_now;
-  new_fragP->fr_next = NULL;
-  /*
-   * Append new frag to current frchain.
-   */
-  former_last_fragP = frcP->frch_last;
-  if (former_last_fragP)
-    {
-      know (former_last_fragP->fr_next == NULL);
-      know (frchain_now->frch_root);
-      former_last_fragP->fr_next = new_fragP;
-    }
-  else
-    {
-      frcP->frch_root = new_fragP;
-    }
-  frcP->frch_last = new_fragP;
+  frag_now = frcP->frch_frag_now;
+
+  assert (frchain_now->frch_last == frag_now);
 }
 
 /*
@@ -367,7 +373,7 @@ subseg_new (segname, subseg)
     return new_seg;
   }
 #else
-  as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname);
+  as_bad (_("Attempt to switch to nonexistent segment \"%s\""), segname);
   return now_seg;
 #endif
 }
@@ -378,13 +384,17 @@ subseg_set (seg, subseg)  /* begin assembly for a new sub-segment */
      register subsegT subseg;
 {
 #ifndef MANY_SEGMENTS
-  know (seg == SEG_DATA || seg == SEG_TEXT || seg == SEG_BSS);
+  know (seg == SEG_DATA
+       || seg == SEG_TEXT
+       || seg == SEG_BSS
+       || seg == SEG_ABSOLUTE);
 #endif
 
   if (seg != now_seg || subseg != now_subseg)
     {                          /* we just changed sub-segments */
       subseg_set_rest (seg, subseg);
     }
+  mri_common_symbol = NULL;
 }
 
 #else /* BFD_ASSEMBLER */
@@ -478,6 +488,7 @@ subseg_set (secptr, subseg)
 {
   if (! (secptr == now_seg && subseg == now_subseg))
     subseg_set_rest (secptr, subseg);
+  mri_common_symbol = NULL;
 }
 
 #ifndef obj_sec_sym_ok_for_reloc
@@ -509,31 +520,140 @@ section_symbol (sec)
     abort ();
   if (seginfo->sym)
     return seginfo->sym;
-  s = symbol_find (sec->name);
-  if (!s)
-    {
+
 #ifndef EMIT_SECTION_SYMBOLS
 #define EMIT_SECTION_SYMBOLS 1
 #endif
 
-      if (EMIT_SECTION_SYMBOLS
+  if (! EMIT_SECTION_SYMBOLS
 #ifdef BFD_ASSEMBLER
-         && symbol_table_frozen
+      || symbol_table_frozen
 #endif
-         )
+      )
+    {
+      /* Here we know it won't be going into the symbol table.  */
+      s = symbol_create (sec->name, sec, 0, &zero_address_frag);
+    }
+  else
+    {
+      s = symbol_find_base (sec->name, 0);
+      if (s == NULL)
        s = symbol_new (sec->name, sec, 0, &zero_address_frag);
       else
-       s = symbol_create (sec->name, sec, 0, &zero_address_frag);
-      S_CLEAR_EXTERNAL (s);
-
-      /* Use the BFD section symbol, if possible.  */
-      if (obj_sec_sym_ok_for_reloc (sec))
-       s->bsym = sec->symbol;
+       {
+         if (S_GET_SEGMENT (s) == undefined_section)
+           {
+             S_SET_SEGMENT (s, sec);
+             symbol_set_frag (s, &zero_address_frag);
+           }
+       }
     }
+
+  S_CLEAR_EXTERNAL (s);
+
+  /* Use the BFD section symbol, if possible.  */
+  if (obj_sec_sym_ok_for_reloc (sec))
+    symbol_set_bfdsym (s, sec->symbol);
+
   seginfo->sym = s;
   return s;
 }
 
 #endif /* BFD_ASSEMBLER */
 
+/* Return whether the specified segment is thought to hold text.  */
+
+#ifndef BFD_ASSEMBLER
+const char * const nontext_section_names[] = {
+  ".eh_frame",
+  ".gcc_except_table",
+#ifdef OBJ_COFF
+#ifndef COFF_LONG_SECTION_NAMES
+  ".eh_fram",
+  ".gcc_exc",
+#endif
+#endif
+  NULL
+};
+#endif /* ! BFD_ASSEMBLER */
+
+int
+subseg_text_p (sec)
+     segT sec;
+{
+#ifdef BFD_ASSEMBLER
+  return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
+#else /* ! BFD_ASSEMBLER */
+  const char * const *p;
+
+  if (sec == data_section || sec == bss_section)
+    return 0;
+
+  for (p = nontext_section_names; *p != NULL; ++p)
+    {
+      if (strcmp (segment_name (sec), *p) == 0)
+       return 0;
+
+#ifdef obj_segment_name
+      if (strcmp (obj_segment_name (sec), *p) == 0)
+       return 0;
+#endif
+    }
+
+  return 1;
+
+#endif /* ! BFD_ASSEMBLER */
+}
+
+void
+subsegs_print_statistics (file)
+     FILE *file;
+{
+  frchainS *frchp;
+  fprintf (file, "frag chains:\n");
+  for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
+    {
+      int count = 0;
+      fragS *fragp;
+
+      /* If frch_subseg is non-zero, it's probably been chained onto
+        the end of a previous subsection.  Don't count it again.  */
+      if (frchp->frch_subseg != 0)
+       continue;
+
+      /* Skip gas-internal sections.  */
+      if (segment_name (frchp->frch_seg)[0] == '*')
+       continue;
+
+      for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
+       {
+#if 0
+         switch (fragp->fr_type)
+           {
+           case rs_fill:
+             fprintf (file, "f"); break;
+           case rs_align:
+             fprintf (file, "a"); break;
+           case rs_align_code:
+             fprintf (file, "c"); break;
+           case rs_org:
+             fprintf (file, "o"); break;
+           case rs_machine_dependent:
+             fprintf (file, "m"); break;
+           case rs_space:
+             fprintf (file, "s"); break;
+           case 0:
+             fprintf (file, "0"); break;
+           default:
+             fprintf (file, "?"); break;
+           }
+#endif
+         count++;
+       }
+      fprintf (file, "\n");
+      fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
+              segment_name (frchp->frch_seg), count);
+    }
+}
+
 /* end of subsegs.c */
This page took 0.02879 seconds and 4 git commands to generate.