diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c
index 6216b1f63ee..b8e049aba46 100644
--- a/gas/config/obj-coff.c
+++ b/gas/config/obj-coff.c
@@ -1804,11 +1804,10 @@ coff_frob_section (segT sec)
 }
 
 void
-obj_coff_init_stab_section (segT seg)
+obj_coff_init_stab_section (segT stab ATTRIBUTE_UNUSED, segT stabstr)
 {
   const char *file;
   char *p;
-  char *stabstr_name;
   unsigned int stroff;
 
   /* Make space for this first symbol.  */
@@ -1816,8 +1815,7 @@ obj_coff_init_stab_section (segT seg)
   /* Zero it out.  */
   memset (p, 0, 12);
   file = as_where ((unsigned int *) NULL);
-  stabstr_name = concat (seg->name, "str", (char *) NULL);
-  stroff = get_stab_string_offset (file, stabstr_name, true);
+  stroff = get_stab_string_offset (file, stabstr);
   know (stroff == 1);
   md_number_to_chars (p, stroff, 4);
 }
diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h
index 2a97c38474f..8c41ac0a5e8 100644
--- a/gas/config/obj-coff.h
+++ b/gas/config/obj-coff.h
@@ -299,7 +299,7 @@ extern const pseudo_typeS coff_pseudo_table[];
 
 /* We need 12 bytes at the start of the section to hold some initial
    information.  */
-#define INIT_STAB_SECTION(seg) obj_coff_init_stab_section (seg)
+#define INIT_STAB_SECTION(stab, str) obj_coff_init_stab_section (stab, str)
 
 /* Store the number of relocations in the section aux entry.  */
 #ifdef OBJ_XCOFF
@@ -342,7 +342,7 @@ extern segT s_get_segment                (symbolS *);
 extern void tc_coff_symbol_emit_hook     (symbolS *);
 #endif
 extern void obj_coff_pe_handle_link_once (void);
-extern void obj_coff_init_stab_section   (segT);
+extern void obj_coff_init_stab_section   (segT, segT);
 extern void c_section_header             (struct internal_scnhdr *,
 					  char *, long, long, long, long,
 					  long, long, long, long);
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 1c1b60b0b48..681e75f9a48 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -2525,27 +2525,25 @@ obj_elf_ident (int ignore ATTRIBUTE_UNUSED)
 /* The first entry in a .stabs section is special.  */
 
 void
-obj_elf_init_stab_section (segT seg)
+obj_elf_init_stab_section (segT stab, segT stabstr)
 {
   char *file;
   char *p;
-  char *stabstr_name;
   unsigned int stroff;
 
   /* Force the section to align to a longword boundary.  Without this,
      UnixWare ar crashes.  */
-  bfd_set_section_alignment (seg, 2);
+  bfd_set_section_alignment (stab, 2);
 
   /* Make space for this first symbol.  */
   p = frag_more (12);
   /* Zero it out.  */
   memset (p, 0, 12);
   file = remap_debug_filename (as_where (NULL));
-  stabstr_name = concat (segment_name (seg), "str", (char *) NULL);
-  stroff = get_stab_string_offset (file, stabstr_name, true);
+  stroff = get_stab_string_offset (file, stabstr);
   know (stroff == 1 || (stroff == 0 && file[0] == '\0'));
   md_number_to_chars (p, stroff, 4);
-  seg_info (seg)->stabu.p = p;
+  seg_info (stab)->stabu.p = p;
   free (file);
 }
 
@@ -3137,12 +3135,12 @@ elf_separate_stab_sections (void)
 }
 
 static void
-elf_init_stab_section (segT seg)
+elf_init_stab_section (segT stab, segT stabstr)
 {
 #ifdef NEED_ECOFF_DEBUG
   if (!ECOFF_DEBUGGING)
 #endif
-    obj_elf_init_stab_section (seg);
+    obj_elf_init_stab_section (stab, stabstr);
 }
 
 /* This is called when the assembler starts.  */
diff --git a/gas/config/obj-elf.h b/gas/config/obj-elf.h
index 5c8404ec49d..683d0851585 100644
--- a/gas/config/obj-elf.h
+++ b/gas/config/obj-elf.h
@@ -242,7 +242,7 @@ void elf_adjust_symtab (void);
 #ifndef SEPARATE_STAB_SECTIONS
 /* Avoid ifndef each separate macro setting by wrapping the whole of the
    stab group on the assumption that whoever sets SEPARATE_STAB_SECTIONS
-   caters to ECOFF_DEBUGGING and the right setting of INIT_STAB_SECTIONS
+   caters to ECOFF_DEBUGGING and the right setting of INIT_STAB_SECTION
    and OBJ_PROCESS_STAB too, without needing the tweaks below.  */
 
 /* Stabs go in a separate section.  */
@@ -250,8 +250,8 @@ void elf_adjust_symtab (void);
 
 /* We need 12 bytes at the start of the section to hold some initial
    information.  */
-extern void obj_elf_init_stab_section (segT);
-#define INIT_STAB_SECTION(seg) obj_elf_init_stab_section (seg)
+extern void obj_elf_init_stab_section (segT, segT);
+#define INIT_STAB_SECTION(stab, str) obj_elf_init_stab_section (stab, str)
 
 #ifdef ECOFF_DEBUGGING
 /* We smuggle stabs in ECOFF rather than using a separate section.
@@ -261,8 +261,8 @@ extern void obj_elf_init_stab_section (segT);
 #define SEPARATE_STAB_SECTIONS (!ECOFF_DEBUGGING)
 
 #undef  INIT_STAB_SECTION
-#define INIT_STAB_SECTION(seg) \
-  ((void) (ECOFF_DEBUGGING ? 0 : (obj_elf_init_stab_section (seg), 0)))
+#define INIT_STAB_SECTION(stab, str) \
+  ((void) (ECOFF_DEBUGGING ? 0 : (obj_elf_init_stab_section (stab, str), 0)))
 
 #undef OBJ_PROCESS_STAB
 #define OBJ_PROCESS_STAB(what, string, type, other, desc)		\
diff --git a/gas/config/obj-multi.h b/gas/config/obj-multi.h
index 894b9245845..4007d8adfb0 100644
--- a/gas/config/obj-multi.h
+++ b/gas/config/obj-multi.h
@@ -153,9 +153,9 @@
 #define SEPARATE_STAB_SECTIONS \
 	((*this_format->separate_stab_sections) ())
 
-#define INIT_STAB_SECTION(S)				\
+#define INIT_STAB_SECTION(STAB, STR)			\
 	(this_format->init_stab_section			\
-	 ? (*this_format->init_stab_section) (S)	\
+	 ? (*this_format->init_stab_section) (STAB, STR) \
 	 : (void) 0)
 
 #define EMIT_SECTION_SYMBOLS (this_format->emit_section_symbols)
diff --git a/gas/config/obj-som.c b/gas/config/obj-som.c
index 9171db29185..6c0c64f94dd 100644
--- a/gas/config/obj-som.c
+++ b/gas/config/obj-som.c
@@ -205,7 +205,7 @@ obj_som_copyright (int unused ATTRIBUTE_UNUSED)
    which BFD does not understand.  */
 
 void
-obj_som_init_stab_section (segT seg)
+obj_som_init_stab_section (segT stab, segT stabstr)
 {
   segT saved_seg = now_seg;
   segT space;
@@ -234,8 +234,8 @@ obj_som_init_stab_section (segT seg)
      (just created above).  Also set some attributes which BFD does
      not understand.  In particular, access bits, sort keys, and load
      quadrant.  */
-  obj_set_subsection_attributes (seg, space, 0x1f, 73, 0, 0, 0, 0);
-  bfd_set_section_alignment (seg, 2);
+  obj_set_subsection_attributes (stab, space, 0x1f, 73, 0, 0, 0, 0);
+  bfd_set_section_alignment (stab, 2);
 
   /* Make some space for the first special stab entry and zero the memory.
      It contains information about the length of this file's
@@ -247,18 +247,17 @@ obj_som_init_stab_section (segT seg)
   p = frag_more (12);
   memset (p, 0, 12);
   file = as_where ((unsigned int *) NULL);
-  stroff = get_stab_string_offset (file, "$GDB_STRINGS$", false);
+  stroff = get_stab_string_offset (file, stabstr);
   know (stroff == 1);
   md_number_to_chars (p, stroff, 4);
-  seg_info (seg)->stabu.p = p;
+  seg_info (stab)->stabu.p = p;
 
   /* Set the containing space for both stab sections to be $GDB_DEBUG$
      (just created above).  Also set some attributes which BFD does
      not understand.  In particular, access bits, sort keys, and load
      quadrant.  */
-  seg = bfd_get_section_by_name (stdoutput, "$GDB_STRINGS$");
-  obj_set_subsection_attributes (seg, space, 0x1f, 72, 0, 0, 0, 0);
-  bfd_set_section_alignment (seg, 2);
+  obj_set_subsection_attributes (stabstr, space, 0x1f, 72, 0, 0, 0, 0);
+  bfd_set_section_alignment (stabstr, 2);
 
   subseg_set (saved_seg, saved_subseg);
 }
diff --git a/gas/config/obj-som.h b/gas/config/obj-som.h
index b04b577e3eb..2c2dd69da8b 100644
--- a/gas/config/obj-som.h
+++ b/gas/config/obj-som.h
@@ -36,7 +36,7 @@
 extern void som_file_symbol           (char *);
 extern void som_frob_file             (void);
 extern void obj_som_version           (int);
-extern void obj_som_init_stab_section (segT);
+extern void obj_som_init_stab_section (segT, segT);
 extern void obj_som_copyright         (int);
 extern void obj_som_compiler          (int);
 
@@ -60,7 +60,7 @@ extern void obj_som_compiler          (int);
 
 /* We use INIT_STAB_SECTION to record the space/subspace relationships
    for the various debugging sections.  */
-#define INIT_STAB_SECTION(seg) obj_som_init_stab_section (seg)
+#define INIT_STAB_SECTION(stab, str) obj_som_init_stab_section (stab, str)
 
 /* We'll be updating the magic 1st stab entry once the entire assembly
    fail has been processed.  */
diff --git a/gas/obj.h b/gas/obj.h
index 3851e67563b..0aebc6a087e 100644
--- a/gas/obj.h
+++ b/gas/obj.h
@@ -65,7 +65,7 @@ struct format_ops {
   void (*generate_asm_lineno) (void);
   void (*process_stab) (int, const char *, int, int, int);
   int (*separate_stab_sections) (void);
-  void (*init_stab_section) (segT);
+  void (*init_stab_section) (segT, segT);
   int (*sec_sym_ok_for_reloc) (asection *);
   void (*pop_insert) (void);
   /* For configurations using ECOFF_DEBUGGING, this callback is used.  */
diff --git a/gas/read.h b/gas/read.h
index 42efce9e79d..523a6e8af43 100644
--- a/gas/read.h
+++ b/gas/read.h
@@ -113,8 +113,7 @@ extern char original_case_string[];
 #endif
 
 extern void pop_insert (const pseudo_typeS *);
-extern unsigned int get_stab_string_offset
-  (const char *, const char *, bool);
+extern unsigned int get_stab_string_offset (const char *, segT);
 extern void aout_process_stab (int, const char *, int, int, int);
 extern char *demand_copy_string (int *lenP);
 extern char *demand_copy_C_string (int *len_pointer);
diff --git a/gas/stabs.c b/gas/stabs.c
index 6a462c4eee7..1b25542900a 100644
--- a/gas/stabs.c
+++ b/gas/stabs.c
@@ -52,9 +52,6 @@ static void generate_asm_file (int, const char *);
    apply to assembler code assembled with -gstabs.  */
 static const char *current_function_label;
 
-/* Current stab section when SEPARATE_STAB_SECTIONS.  */
-static segT cached_sec;
-
 /* State used by generate_asm_file.  */
 static char *last_asm_file;
 static int file_label_count;
@@ -95,14 +92,12 @@ static int endfunc_label_count;
 #endif
 
 unsigned int
-get_stab_string_offset (const char *string, const char *stabstr_secname,
-			bool free_stabstr_secname)
+get_stab_string_offset (const char *string, segT stabstr)
 {
   unsigned int length;
   unsigned int retval;
   segT save_seg;
   subsegT save_subseg;
-  segT seg;
   char *p;
 
   if (! SEPARATE_STAB_SECTIONS)
@@ -113,19 +108,16 @@ get_stab_string_offset (const char *string, const char *stabstr_secname,
   save_seg = now_seg;
   save_subseg = now_subseg;
 
-  /* Create the stab string section, if it doesn't already exist.  */
-  seg = subseg_new (stabstr_secname, 0);
-  if (free_stabstr_secname && seg->name != stabstr_secname)
-    free ((char *) stabstr_secname);
+  subseg_set (stabstr, 0);
 
-  retval = seg_info (seg)->stabu.stab_string_size;
+  retval = seg_info (stabstr)->stabu.stab_string_size;
   if (retval <= 0)
     {
       /* Make sure the first string is empty.  */
       p = frag_more (1);
       *p = 0;
-      retval = seg_info (seg)->stabu.stab_string_size = 1;
-      bfd_set_section_flags (seg, SEC_READONLY | SEC_DEBUGGING);
+      retval = seg_info (stabstr)->stabu.stab_string_size = 1;
+      bfd_set_section_flags (stabstr, SEC_READONLY | SEC_DEBUGGING);
     }
 
   if (length > 0)
@@ -133,7 +125,7 @@ get_stab_string_offset (const char *string, const char *stabstr_secname,
       p = frag_more (length + 1);
       strcpy (p, string);
 
-      seg_info (seg)->stabu.stab_string_size += length + 1;
+      seg_info (stabstr)->stabu.stab_string_size += length + 1;
     }
   else
     retval = 0;
@@ -184,23 +176,71 @@ aout_process_stab (int what, const char *string, int type, int other, int desc)
 }
 #endif
 
+static bool
+eat_comma (int what)
+{
+  if (*input_line_pointer == ',')
+    {
+      input_line_pointer++;
+      return true;
+    }
+  as_warn (_(".stab%c: missing comma"), what);
+  ignore_rest_of_line ();
+  return false;
+}
+
 /* This can handle different kinds of stabs (s,n,d) and different
-   kinds of stab sections.  If STAB_SECNAME_OBSTACK_END is non-NULL,
-   then STAB_SECNAME and STABSTR_SECNAME will be freed if possible
-   before this function returns (the former by obstack_free).  */
+   kinds of stab sections.  If FREENAMES is true, then STAB_SECNAME
+   and STABSTR_SECNAME are allocated in that order on the notes
+   obstack and will be freed if possible.  */
 
 static void
 s_stab_generic (int what,
 		const char *stab_secname,
 		const char *stabstr_secname,
-		const char *stab_secname_obstack_end)
+		bool freenames)
 {
-  long longint;
   const char *string;
   char *saved_string_obstack_end;
   int type;
   int other;
   int desc;
+  segT stab, stabstr = NULL;
+  segT saved_seg = now_seg;
+  subsegT saved_subseg = now_subseg;
+  fragS *saved_frag = frag_now;
+  valueT dot = 0;
+
+  if (SEPARATE_STAB_SECTIONS)
+    /* Output the stab information in a separate section.  This is used
+       at least for COFF and ELF.  */
+    {
+      dot = frag_now_fix ();
+
+#ifdef md_flush_pending_output
+      md_flush_pending_output ();
+#endif
+      stab = subseg_new (stab_secname, 0);
+      stabstr = subseg_new (stabstr_secname, 0);
+
+      if (freenames
+	  && stab->name != stab_secname
+	  && stabstr->name != stabstr_secname)
+	obstack_free (&notes, stab_secname);
+
+      subseg_set (stab, 0);
+      if (!seg_info (stab)->hadone)
+	{
+	  bfd_set_section_flags (stab,
+				 SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
+#ifdef INIT_STAB_SECTION
+	  INIT_STAB_SECTION (stab, stabstr);
+#endif
+	  seg_info (stab)->hadone = 1;
+	}
+    }
+  else if (freenames)
+    obstack_free (&notes, stab_secname);
 
   /* The general format is:
      .stabs "STRING",TYPE,OTHER,DESC,VALUE
@@ -210,11 +250,9 @@ s_stab_generic (int what,
      any trailing whitespace.  The argument what is one of 's', 'n' or
      'd' indicating which type of .stab this is.  */
 
+  saved_string_obstack_end = NULL;
   if (what != 's')
-    {
-      string = "";
-      saved_string_obstack_end = 0;
-    }
+    string = "";
   else
     {
       int length;
@@ -224,38 +262,24 @@ s_stab_generic (int what,
 	{
 	  as_warn (_(".stab%c: missing string"), what);
 	  ignore_rest_of_line ();
-	  return;
+	  goto out;
 	}
       /* FIXME: We should probably find some other temporary storage
 	 for string, rather than leaking memory if someone else
 	 happens to use the notes obstack.  */
       saved_string_obstack_end = obstack_next_free (&notes);
       SKIP_WHITESPACE ();
-      if (*input_line_pointer == ',')
-	input_line_pointer++;
-      else
-	{
-	  as_warn (_(".stab%c: missing comma"), what);
-	  ignore_rest_of_line ();
-	  return;
-	}
+      if (!eat_comma (what))
+	goto out;
     }
 
-  if (get_absolute_expression_and_terminator (&longint) != ',')
-    {
-      as_warn (_(".stab%c: missing comma"), what);
-      ignore_rest_of_line ();
-      return;
-    }
-  type = longint;
+  type = get_absolute_expression ();
+  if (!eat_comma (what))
+    goto out;
 
-  if (get_absolute_expression_and_terminator (&longint) != ',')
-    {
-      as_warn (_(".stab%c: missing comma"), what);
-      ignore_rest_of_line ();
-      return;
-    }
-  other = longint;
+  other = get_absolute_expression ();
+  if (!eat_comma (what))
+    goto out;
 
   desc = get_absolute_expression ();
 
@@ -268,13 +292,8 @@ s_stab_generic (int what,
 
   if (what == 's' || what == 'n')
     {
-      if (*input_line_pointer != ',')
-	{
-	  as_warn (_(".stab%c: missing comma"), what);
-	  ignore_rest_of_line ();
-	  return;
-	}
-      input_line_pointer++;
+      if (!eat_comma (what))
+	goto out;
       SKIP_WHITESPACE ();
     }
 
@@ -322,54 +341,16 @@ s_stab_generic (int what,
     /* Output the stab information in a separate section.  This is used
        at least for COFF and ELF.  */
     {
-      segT saved_seg = now_seg;
-      subsegT saved_subseg = now_subseg;
-      fragS *saved_frag = frag_now;
-      valueT dot;
-      segT seg;
       unsigned int stroff;
       char *p;
 
-      dot = frag_now_fix ();
-
-#ifdef md_flush_pending_output
-      md_flush_pending_output ();
-#endif
+      stroff = get_stab_string_offset (string, stabstr);
 
-      if (cached_sec && strcmp (cached_sec->name, stab_secname) == 0)
-	{
-	  seg = cached_sec;
-	  subseg_set (seg, 0);
-	}
-      else
-	{
-	  seg = subseg_new (stab_secname, 0);
-	  cached_sec = seg;
-	}
-
-      if (! seg_info (seg)->hadone)
-	{
-	  bfd_set_section_flags (seg,
-				 SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
-#ifdef INIT_STAB_SECTION
-	  INIT_STAB_SECTION (seg);
-#endif
-	  seg_info (seg)->hadone = 1;
-	}
-
-      stroff = get_stab_string_offset (string, stabstr_secname,
-				       stab_secname_obstack_end != NULL);
-
-      /* Release the string, if nobody else has used the obstack.  */
-      if (saved_string_obstack_end != NULL
-	  && saved_string_obstack_end == obstack_next_free (&notes))
+      /* Release the string, if nobody else has used the obstack.
+	 This must be done before creating symbols below, which uses
+	 the notes obstack.  */
+      if (saved_string_obstack_end == obstack_next_free (&notes))
 	obstack_free (&notes, string);
-      /* Similarly for the section name.  This must be done before
-	 creating symbols below, which uses the notes obstack.  */
-      if (seg->name != stab_secname
-	  && stab_secname_obstack_end != NULL
-	  && stab_secname_obstack_end == obstack_next_free (&notes))
-	obstack_free (&notes, stab_secname);
 
       /* At least for now, stabs in a special stab section are always
 	 output as 12 byte blocks of information.  */
@@ -403,17 +384,9 @@ s_stab_generic (int what,
 #ifdef OBJ_PROCESS_STAB
       OBJ_PROCESS_STAB (what, string, type, other, desc);
 #endif
-
-      subseg_set (saved_seg, saved_subseg);
     }
   else
     {
-      if (stab_secname_obstack_end != NULL)
-	{
-	  free ((char *) stabstr_secname);
-	  if (stab_secname_obstack_end == obstack_next_free (&notes))
-	    obstack_free (&notes, stab_secname);
-	}
 #ifdef OBJ_PROCESS_STAB
       OBJ_PROCESS_STAB (what, string, type, other, desc);
 #else
@@ -422,6 +395,10 @@ s_stab_generic (int what,
     }
 
   demand_empty_rest_of_line ();
+ out:
+  if (saved_string_obstack_end == obstack_next_free (&notes))
+    obstack_free (&notes, string);
+  subseg_set (saved_seg, saved_subseg);
 }
 
 /* Regular stab directive.  */
@@ -429,7 +406,7 @@ s_stab_generic (int what,
 void
 s_stab (int what)
 {
-  s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME, NULL);
+  s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME, false);
 }
 
 /* "Extended stabs", used in Solaris only now.  */
@@ -438,25 +415,23 @@ void
 s_xstab (int what)
 {
   int length;
-  char *stab_secname, *stabstr_secname, *stab_secname_obstack_end;
+  char *stab_secname, *stabstr_secname;
 
   stab_secname = demand_copy_C_string (&length);
-  stab_secname_obstack_end = obstack_next_free (&notes);
   SKIP_WHITESPACE ();
   if (*input_line_pointer == ',')
-    input_line_pointer++;
+    {
+      input_line_pointer++;
+      /* To get the name of the stab string section, simply add
+	 "str" to the stab section name.  */
+      stabstr_secname = notes_concat (stab_secname, "str", (char *) NULL);
+      s_stab_generic (what, stab_secname, stabstr_secname, true);
+    }
   else
     {
       as_bad (_("comma missing in .xstabs"));
       ignore_rest_of_line ();
-      return;
     }
-
-  /* To get the name of the stab string section, simply add "str" to
-     the stab section name.  */
-  stabstr_secname = concat (stab_secname, "str", (char *) NULL);
-  s_stab_generic (what, stab_secname, stabstr_secname,
-		  stab_secname_obstack_end);
 }
 
 #ifdef S_SET_DESC
@@ -707,7 +682,6 @@ void
 stabs_begin (void)
 {
   current_function_label = NULL;
-  cached_sec = NULL;
   last_asm_file = NULL;
   file_label_count = 0;
   line_label_count = 0;
