xref: /openbsd-src/gnu/usr.bin/binutils-2.17/gas/subsegs.c (revision a51f8248c4852d1631cfe0f5c1956f852b4cf6dc)
13d8817e4Smiod /* subsegs.c - subsegments -
23d8817e4Smiod    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
33d8817e4Smiod    1999, 2000, 2001, 2002, 2003, 2004, 2005
43d8817e4Smiod    Free Software Foundation, Inc.
53d8817e4Smiod 
63d8817e4Smiod    This file is part of GAS, the GNU Assembler.
73d8817e4Smiod 
83d8817e4Smiod    GAS is free software; you can redistribute it and/or modify
93d8817e4Smiod    it under the terms of the GNU General Public License as published by
103d8817e4Smiod    the Free Software Foundation; either version 2, or (at your option)
113d8817e4Smiod    any later version.
123d8817e4Smiod 
133d8817e4Smiod    GAS is distributed in the hope that it will be useful,
143d8817e4Smiod    but WITHOUT ANY WARRANTY; without even the implied warranty of
153d8817e4Smiod    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
163d8817e4Smiod    GNU General Public License for more details.
173d8817e4Smiod 
183d8817e4Smiod    You should have received a copy of the GNU General Public License
193d8817e4Smiod    along with GAS; see the file COPYING.  If not, write to the Free
203d8817e4Smiod    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
213d8817e4Smiod    02110-1301, USA.  */
223d8817e4Smiod 
233d8817e4Smiod /* Segments & sub-segments.  */
243d8817e4Smiod 
253d8817e4Smiod #include "as.h"
263d8817e4Smiod 
273d8817e4Smiod #include "subsegs.h"
283d8817e4Smiod #include "obstack.h"
293d8817e4Smiod 
303d8817e4Smiod frchainS *frchain_root, *frchain_now;
313d8817e4Smiod 
323d8817e4Smiod static struct obstack frchains;
333d8817e4Smiod 
343d8817e4Smiod /* Gas segment information for bfd_abs_section_ptr and
353d8817e4Smiod    bfd_und_section_ptr.  */
363d8817e4Smiod static segment_info_type *abs_seg_info;
373d8817e4Smiod static segment_info_type *und_seg_info;
383d8817e4Smiod 
393d8817e4Smiod static void subseg_set_rest (segT, subsegT);
403d8817e4Smiod 
413d8817e4Smiod static fragS dummy_frag;
423d8817e4Smiod 
433d8817e4Smiod static frchainS absolute_frchain;
443d8817e4Smiod 
453d8817e4Smiod void
subsegs_begin(void)463d8817e4Smiod subsegs_begin (void)
473d8817e4Smiod {
483d8817e4Smiod   obstack_begin (&frchains, chunksize);
493d8817e4Smiod #if __GNUC__ >= 2
503d8817e4Smiod   obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
513d8817e4Smiod #endif
523d8817e4Smiod 
533d8817e4Smiod   frchain_root = NULL;
543d8817e4Smiod   frchain_now = NULL;		/* Warn new_subseg() that we are booting.  */
553d8817e4Smiod 
563d8817e4Smiod   frag_now = &dummy_frag;
573d8817e4Smiod 
583d8817e4Smiod   absolute_frchain.frch_seg = absolute_section;
593d8817e4Smiod   absolute_frchain.frch_subseg = 0;
603d8817e4Smiod   absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
613d8817e4Smiod   absolute_frchain.frch_frag_now = &zero_address_frag;
623d8817e4Smiod   absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
633d8817e4Smiod }
643d8817e4Smiod 
653d8817e4Smiod /*
663d8817e4Smiod  *			subseg_change()
673d8817e4Smiod  *
683d8817e4Smiod  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
693d8817e4Smiod  * subsegment. If we are already in the correct subsegment, change nothing.
703d8817e4Smiod  * This is used eg as a worker for subseg_set [which does make a new frag_now]
713d8817e4Smiod  * and for changing segments after we have read the source. We construct eg
723d8817e4Smiod  * fixSs even after the source file is read, so we do have to keep the
733d8817e4Smiod  * segment context correct.
743d8817e4Smiod  */
753d8817e4Smiod void
subseg_change(register segT seg,register int subseg)763d8817e4Smiod subseg_change (register segT seg, register int subseg)
773d8817e4Smiod {
783d8817e4Smiod   segment_info_type *seginfo;
793d8817e4Smiod   now_seg = seg;
803d8817e4Smiod   now_subseg = subseg;
813d8817e4Smiod 
823d8817e4Smiod   if (now_seg == absolute_section)
833d8817e4Smiod     return;
843d8817e4Smiod 
853d8817e4Smiod   seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
863d8817e4Smiod   if (! seginfo)
873d8817e4Smiod     {
883d8817e4Smiod       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
893d8817e4Smiod       memset ((PTR) seginfo, 0, sizeof (*seginfo));
903d8817e4Smiod       seginfo->fix_root = NULL;
913d8817e4Smiod       seginfo->fix_tail = NULL;
923d8817e4Smiod       seginfo->bfd_section = seg;
933d8817e4Smiod       seginfo->sym = 0;
943d8817e4Smiod       if (seg == bfd_abs_section_ptr)
953d8817e4Smiod 	abs_seg_info = seginfo;
963d8817e4Smiod       else if (seg == bfd_und_section_ptr)
973d8817e4Smiod 	und_seg_info = seginfo;
983d8817e4Smiod       else
993d8817e4Smiod 	bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
1003d8817e4Smiod     }
1013d8817e4Smiod }
1023d8817e4Smiod 
1033d8817e4Smiod static void
subseg_set_rest(segT seg,subsegT subseg)1043d8817e4Smiod subseg_set_rest (segT seg, subsegT subseg)
1053d8817e4Smiod {
1063d8817e4Smiod   register frchainS *frcP;	/* crawl frchain chain */
1073d8817e4Smiod   register frchainS **lastPP;	/* address of last pointer */
1083d8817e4Smiod   frchainS *newP;		/* address of new frchain */
1093d8817e4Smiod 
1103d8817e4Smiod   mri_common_symbol = NULL;
1113d8817e4Smiod 
1123d8817e4Smiod   if (frag_now && frchain_now)
1133d8817e4Smiod     frchain_now->frch_frag_now = frag_now;
1143d8817e4Smiod 
1153d8817e4Smiod   assert (frchain_now == 0
1163d8817e4Smiod 	  || now_seg == undefined_section
1173d8817e4Smiod 	  || now_seg == absolute_section
1183d8817e4Smiod 	  || frchain_now->frch_last == frag_now);
1193d8817e4Smiod 
1203d8817e4Smiod   subseg_change (seg, (int) subseg);
1213d8817e4Smiod 
1223d8817e4Smiod   if (seg == absolute_section)
1233d8817e4Smiod     {
1243d8817e4Smiod       frchain_now = &absolute_frchain;
1253d8817e4Smiod       frag_now = &zero_address_frag;
1263d8817e4Smiod       return;
1273d8817e4Smiod     }
1283d8817e4Smiod 
1293d8817e4Smiod   assert (frchain_now == 0
1303d8817e4Smiod 	  || now_seg == undefined_section
1313d8817e4Smiod 	  || frchain_now->frch_last == frag_now);
1323d8817e4Smiod 
1333d8817e4Smiod   /*
1343d8817e4Smiod    * Attempt to find or make a frchain for that sub seg.
1353d8817e4Smiod    * Crawl along chain of frchainSs, begins @ frchain_root.
1363d8817e4Smiod    * If we need to make a frchainS, link it into correct
1373d8817e4Smiod    * position of chain rooted in frchain_root.
1383d8817e4Smiod    */
1393d8817e4Smiod   for (frcP = *(lastPP = &frchain_root);
1403d8817e4Smiod        frcP && frcP->frch_seg <= seg;
1413d8817e4Smiod        frcP = *(lastPP = &frcP->frch_next))
1423d8817e4Smiod     {
1433d8817e4Smiod       if (frcP->frch_seg == seg
1443d8817e4Smiod 	  && frcP->frch_subseg >= subseg)
1453d8817e4Smiod 	{
1463d8817e4Smiod 	  break;
1473d8817e4Smiod 	}
1483d8817e4Smiod     }
1493d8817e4Smiod   /*
1503d8817e4Smiod    * frcP:		Address of the 1st frchainS in correct segment with
1513d8817e4Smiod    *		frch_subseg >= subseg.
1523d8817e4Smiod    *		We want to either use this frchainS, or we want
1533d8817e4Smiod    *		to insert a new frchainS just before it.
1543d8817e4Smiod    *
1553d8817e4Smiod    *		If frcP==NULL, then we are at the end of the chain
1563d8817e4Smiod    *		of frchainS-s. A NULL frcP means we fell off the end
1573d8817e4Smiod    *		of the chain looking for a
1583d8817e4Smiod    *		frch_subseg >= subseg, so we
1593d8817e4Smiod    *		must make a new frchainS.
1603d8817e4Smiod    *
1613d8817e4Smiod    *		If we ever maintain a pointer to
1623d8817e4Smiod    *		the last frchainS in the chain, we change that pointer
1633d8817e4Smiod    *		ONLY when frcP==NULL.
1643d8817e4Smiod    *
1653d8817e4Smiod    * lastPP:	Address of the pointer with value frcP;
1663d8817e4Smiod    *		Never NULL.
1673d8817e4Smiod    *		May point to frchain_root.
1683d8817e4Smiod    *
1693d8817e4Smiod    */
1703d8817e4Smiod   if (!frcP
1713d8817e4Smiod       || (frcP->frch_seg > seg
1723d8817e4Smiod 	  || frcP->frch_subseg > subseg))	/* Kinky logic only works with 2 segments.  */
1733d8817e4Smiod     {
1743d8817e4Smiod       /*
1753d8817e4Smiod        * This should be the only code that creates a frchainS.
1763d8817e4Smiod        */
1773d8817e4Smiod       segment_info_type *seginfo;
1783d8817e4Smiod 
1793d8817e4Smiod       newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
1803d8817e4Smiod       newP->frch_subseg = subseg;
1813d8817e4Smiod       newP->frch_seg = seg;
1823d8817e4Smiod       newP->fix_root = NULL;
1833d8817e4Smiod       newP->fix_tail = NULL;
1843d8817e4Smiod       obstack_begin (&newP->frch_obstack, chunksize);
1853d8817e4Smiod #if __GNUC__ >= 2
1863d8817e4Smiod       obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
1873d8817e4Smiod #endif
1883d8817e4Smiod       newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
1893d8817e4Smiod       newP->frch_frag_now->fr_type = rs_fill;
190*a51f8248Skettenis       newP->frch_cfi_data = NULL;
1913d8817e4Smiod 
1923d8817e4Smiod       newP->frch_root = newP->frch_last = newP->frch_frag_now;
1933d8817e4Smiod 
1943d8817e4Smiod       *lastPP = newP;
1953d8817e4Smiod       newP->frch_next = frcP;	/* perhaps NULL */
1963d8817e4Smiod 
1973d8817e4Smiod       seginfo = seg_info (seg);
1983d8817e4Smiod       if (seginfo && (!seginfo->frchainP || seginfo->frchainP == frcP))
1993d8817e4Smiod 	seginfo->frchainP = newP;
2003d8817e4Smiod 
2013d8817e4Smiod       frcP = newP;
2023d8817e4Smiod     }
2033d8817e4Smiod   /*
2043d8817e4Smiod    * Here with frcP pointing to the frchainS for subseg.
2053d8817e4Smiod    */
2063d8817e4Smiod   frchain_now = frcP;
2073d8817e4Smiod   frag_now = frcP->frch_frag_now;
2083d8817e4Smiod 
2093d8817e4Smiod   assert (frchain_now->frch_last == frag_now);
2103d8817e4Smiod }
2113d8817e4Smiod 
2123d8817e4Smiod /*
2133d8817e4Smiod  *			subseg_set(segT, subsegT)
2143d8817e4Smiod  *
2153d8817e4Smiod  * If you attempt to change to the current subsegment, nothing happens.
2163d8817e4Smiod  *
2173d8817e4Smiod  * In:	segT, subsegT code for new subsegment.
2183d8817e4Smiod  *	frag_now -> incomplete frag for current subsegment.
2193d8817e4Smiod  *	If frag_now==NULL, then there is no old, incomplete frag, so
2203d8817e4Smiod  *	the old frag is not closed off.
2213d8817e4Smiod  *
2223d8817e4Smiod  * Out:	now_subseg, now_seg updated.
2233d8817e4Smiod  *	Frchain_now points to the (possibly new) struct frchain for this
2243d8817e4Smiod  *	sub-segment.
2253d8817e4Smiod  *	Frchain_root updated if needed.
2263d8817e4Smiod  */
2273d8817e4Smiod 
2283d8817e4Smiod segT
subseg_get(const char * segname,int force_new)2293d8817e4Smiod subseg_get (const char *segname, int force_new)
2303d8817e4Smiod {
2313d8817e4Smiod   segT secptr;
2323d8817e4Smiod   segment_info_type *seginfo;
2333d8817e4Smiod   const char *now_seg_name = (now_seg
2343d8817e4Smiod 			      ? bfd_get_section_name (stdoutput, now_seg)
2353d8817e4Smiod 			      : 0);
2363d8817e4Smiod 
2373d8817e4Smiod   if (!force_new
2383d8817e4Smiod       && now_seg_name
2393d8817e4Smiod       && (now_seg_name == segname
2403d8817e4Smiod 	  || !strcmp (now_seg_name, segname)))
2413d8817e4Smiod     return now_seg;
2423d8817e4Smiod 
2433d8817e4Smiod   if (!force_new)
2443d8817e4Smiod     secptr = bfd_make_section_old_way (stdoutput, segname);
2453d8817e4Smiod   else
2463d8817e4Smiod     secptr = bfd_make_section_anyway (stdoutput, segname);
2473d8817e4Smiod 
2483d8817e4Smiod #ifdef obj_sec_set_private_data
2493d8817e4Smiod   obj_sec_set_private_data (stdoutput, secptr);
2503d8817e4Smiod #endif
2513d8817e4Smiod 
2523d8817e4Smiod   seginfo = seg_info (secptr);
2533d8817e4Smiod   if (! seginfo)
2543d8817e4Smiod     {
2553d8817e4Smiod       /* Check whether output_section is set first because secptr may
2563d8817e4Smiod 	 be bfd_abs_section_ptr.  */
2573d8817e4Smiod       if (secptr->output_section != secptr)
2583d8817e4Smiod 	secptr->output_section = secptr;
2593d8817e4Smiod       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
2603d8817e4Smiod       memset ((PTR) seginfo, 0, sizeof (*seginfo));
2613d8817e4Smiod       seginfo->fix_root = NULL;
2623d8817e4Smiod       seginfo->fix_tail = NULL;
2633d8817e4Smiod       seginfo->bfd_section = secptr;
2643d8817e4Smiod       if (secptr == bfd_abs_section_ptr)
2653d8817e4Smiod 	abs_seg_info = seginfo;
2663d8817e4Smiod       else if (secptr == bfd_und_section_ptr)
2673d8817e4Smiod 	und_seg_info = seginfo;
2683d8817e4Smiod       else
2693d8817e4Smiod 	bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
2703d8817e4Smiod       seginfo->frchainP = NULL;
2713d8817e4Smiod       seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
2723d8817e4Smiod       seginfo->sym = NULL;
2733d8817e4Smiod       seginfo->dot = NULL;
2743d8817e4Smiod     }
2753d8817e4Smiod   return secptr;
2763d8817e4Smiod }
2773d8817e4Smiod 
2783d8817e4Smiod segT
subseg_new(const char * segname,subsegT subseg)2793d8817e4Smiod subseg_new (const char *segname, subsegT subseg)
2803d8817e4Smiod {
2813d8817e4Smiod   segT secptr;
2823d8817e4Smiod   segment_info_type *seginfo;
2833d8817e4Smiod 
2843d8817e4Smiod   secptr = subseg_get (segname, 0);
2853d8817e4Smiod   subseg_set_rest (secptr, subseg);
2863d8817e4Smiod   seginfo = seg_info (secptr);
2873d8817e4Smiod   if (! seginfo->frchainP)
2883d8817e4Smiod     seginfo->frchainP = frchain_now;
2893d8817e4Smiod   return secptr;
2903d8817e4Smiod }
2913d8817e4Smiod 
2923d8817e4Smiod /* Like subseg_new, except a new section is always created, even if
2933d8817e4Smiod    a section with that name already exists.  */
2943d8817e4Smiod segT
subseg_force_new(const char * segname,subsegT subseg)2953d8817e4Smiod subseg_force_new (const char *segname, subsegT subseg)
2963d8817e4Smiod {
2973d8817e4Smiod   segT secptr;
2983d8817e4Smiod   segment_info_type *seginfo;
2993d8817e4Smiod 
3003d8817e4Smiod   secptr = subseg_get (segname, 1);
3013d8817e4Smiod   subseg_set_rest (secptr, subseg);
3023d8817e4Smiod   seginfo = seg_info (secptr);
3033d8817e4Smiod   if (! seginfo->frchainP)
3043d8817e4Smiod     seginfo->frchainP = frchain_now;
3053d8817e4Smiod   return secptr;
3063d8817e4Smiod }
3073d8817e4Smiod 
3083d8817e4Smiod void
subseg_set(segT secptr,subsegT subseg)3093d8817e4Smiod subseg_set (segT secptr, subsegT subseg)
3103d8817e4Smiod {
3113d8817e4Smiod   if (! (secptr == now_seg && subseg == now_subseg))
3123d8817e4Smiod     subseg_set_rest (secptr, subseg);
3133d8817e4Smiod   mri_common_symbol = NULL;
3143d8817e4Smiod }
3153d8817e4Smiod 
3163d8817e4Smiod #ifndef obj_sec_sym_ok_for_reloc
3173d8817e4Smiod #define obj_sec_sym_ok_for_reloc(SEC)	0
3183d8817e4Smiod #endif
3193d8817e4Smiod 
3203d8817e4Smiod /* Get the gas information we are storing for a section.  */
3213d8817e4Smiod 
3223d8817e4Smiod segment_info_type *
seg_info(segT sec)3233d8817e4Smiod seg_info (segT sec)
3243d8817e4Smiod {
3253d8817e4Smiod   if (sec == bfd_abs_section_ptr)
3263d8817e4Smiod     return abs_seg_info;
3273d8817e4Smiod   else if (sec == bfd_und_section_ptr)
3283d8817e4Smiod     return und_seg_info;
3293d8817e4Smiod   else
3303d8817e4Smiod     return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
3313d8817e4Smiod }
3323d8817e4Smiod 
3333d8817e4Smiod symbolS *
section_symbol(segT sec)3343d8817e4Smiod section_symbol (segT sec)
3353d8817e4Smiod {
3363d8817e4Smiod   segment_info_type *seginfo = seg_info (sec);
3373d8817e4Smiod   symbolS *s;
3383d8817e4Smiod 
3393d8817e4Smiod   if (seginfo == 0)
3403d8817e4Smiod     abort ();
3413d8817e4Smiod   if (seginfo->sym)
3423d8817e4Smiod     return seginfo->sym;
3433d8817e4Smiod 
3443d8817e4Smiod #ifndef EMIT_SECTION_SYMBOLS
3453d8817e4Smiod #define EMIT_SECTION_SYMBOLS 1
3463d8817e4Smiod #endif
3473d8817e4Smiod 
3483d8817e4Smiod   if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
3493d8817e4Smiod     {
3503d8817e4Smiod       /* Here we know it won't be going into the symbol table.  */
3513d8817e4Smiod       s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
3523d8817e4Smiod     }
3533d8817e4Smiod   else
3543d8817e4Smiod     {
3553d8817e4Smiod       segT seg;
3563d8817e4Smiod       s = symbol_find (sec->symbol->name);
3573d8817e4Smiod       /* We have to make sure it is the right symbol when we
3583d8817e4Smiod 	 have multiple sections with the same section name.  */
3593d8817e4Smiod       if (s == NULL
3603d8817e4Smiod 	  || ((seg = S_GET_SEGMENT (s)) != sec
3613d8817e4Smiod 	      && seg != undefined_section))
3623d8817e4Smiod 	s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
3633d8817e4Smiod       else if (seg == undefined_section)
3643d8817e4Smiod 	{
3653d8817e4Smiod 	  S_SET_SEGMENT (s, sec);
3663d8817e4Smiod 	  symbol_set_frag (s, &zero_address_frag);
3673d8817e4Smiod 	}
3683d8817e4Smiod     }
3693d8817e4Smiod 
3703d8817e4Smiod   S_CLEAR_EXTERNAL (s);
3713d8817e4Smiod 
3723d8817e4Smiod   /* Use the BFD section symbol, if possible.  */
3733d8817e4Smiod   if (obj_sec_sym_ok_for_reloc (sec))
3743d8817e4Smiod     symbol_set_bfdsym (s, sec->symbol);
3753d8817e4Smiod   else
3763d8817e4Smiod     symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
3773d8817e4Smiod 
3783d8817e4Smiod   seginfo->sym = s;
3793d8817e4Smiod   return s;
3803d8817e4Smiod }
3813d8817e4Smiod 
3823d8817e4Smiod /* Return whether the specified segment is thought to hold text.  */
3833d8817e4Smiod 
3843d8817e4Smiod int
subseg_text_p(segT sec)3853d8817e4Smiod subseg_text_p (segT sec)
3863d8817e4Smiod {
3873d8817e4Smiod   return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
3883d8817e4Smiod }
3893d8817e4Smiod 
3903d8817e4Smiod /* Return non zero if SEC has at least one byte of data.  It is
3913d8817e4Smiod    possible that we'll return zero even on a non-empty section because
3923d8817e4Smiod    we don't know all the fragment types, and it is possible that an
3933d8817e4Smiod    fr_fix == 0 one still contributes data.  Think of this as
3943d8817e4Smiod    seg_definitely_not_empty_p.  */
3953d8817e4Smiod 
3963d8817e4Smiod int
seg_not_empty_p(segT sec ATTRIBUTE_UNUSED)3973d8817e4Smiod seg_not_empty_p (segT sec ATTRIBUTE_UNUSED)
3983d8817e4Smiod {
3993d8817e4Smiod   segment_info_type *seginfo = seg_info (sec);
4003d8817e4Smiod   frchainS *chain;
4013d8817e4Smiod   fragS *frag;
4023d8817e4Smiod 
4033d8817e4Smiod   if (!seginfo)
4043d8817e4Smiod     return 0;
4053d8817e4Smiod 
4063d8817e4Smiod   for (chain = seginfo->frchainP; chain; chain = chain->frch_next)
4073d8817e4Smiod     {
4083d8817e4Smiod       for (frag = chain->frch_root; frag; frag = frag->fr_next)
4093d8817e4Smiod 	if (frag->fr_fix)
4103d8817e4Smiod 	  return 1;
4113d8817e4Smiod       if (obstack_next_free (&chain->frch_obstack)
4123d8817e4Smiod 	  != chain->frch_last->fr_literal)
4133d8817e4Smiod 	return 1;
4143d8817e4Smiod     }
4153d8817e4Smiod   return 0;
4163d8817e4Smiod }
4173d8817e4Smiod 
4183d8817e4Smiod void
subsegs_print_statistics(FILE * file)4193d8817e4Smiod subsegs_print_statistics (FILE *file)
4203d8817e4Smiod {
4213d8817e4Smiod   frchainS *frchp;
4223d8817e4Smiod   fprintf (file, "frag chains:\n");
4233d8817e4Smiod   for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
4243d8817e4Smiod     {
4253d8817e4Smiod       int count = 0;
4263d8817e4Smiod       fragS *fragp;
4273d8817e4Smiod 
4283d8817e4Smiod       /* If frch_subseg is non-zero, it's probably been chained onto
4293d8817e4Smiod 	 the end of a previous subsection.  Don't count it again.  */
4303d8817e4Smiod       if (frchp->frch_subseg != 0)
4313d8817e4Smiod 	continue;
4323d8817e4Smiod 
4333d8817e4Smiod       /* Skip gas-internal sections.  */
4343d8817e4Smiod       if (segment_name (frchp->frch_seg)[0] == '*')
4353d8817e4Smiod 	continue;
4363d8817e4Smiod 
4373d8817e4Smiod       for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
4383d8817e4Smiod 	{
4393d8817e4Smiod 	  count++;
4403d8817e4Smiod 	}
4413d8817e4Smiod       fprintf (file, "\n");
4423d8817e4Smiod       fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
4433d8817e4Smiod 	       segment_name (frchp->frch_seg), count);
4443d8817e4Smiod     }
4453d8817e4Smiod }
4463d8817e4Smiod 
4473d8817e4Smiod /* end of subsegs.c */
448