xref: /openbsd-src/gnu/usr.bin/binutils/gas/subsegs.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* subsegs.c - subsegments -
2b55d4692Sfgsch    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3c074d1c9Sdrahn    1999, 2000, 2002
42159047fSniklas    Free Software Foundation, Inc.
52159047fSniklas 
62159047fSniklas    This file is part of GAS, the GNU Assembler.
72159047fSniklas 
82159047fSniklas    GAS is free software; you can redistribute it and/or modify
92159047fSniklas    it under the terms of the GNU General Public License as published by
102159047fSniklas    the Free Software Foundation; either version 2, or (at your option)
112159047fSniklas    any later version.
122159047fSniklas 
132159047fSniklas    GAS is distributed in the hope that it will be useful,
142159047fSniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
152159047fSniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
162159047fSniklas    GNU General Public License for more details.
172159047fSniklas 
182159047fSniklas    You should have received a copy of the GNU General Public License
190c6d0228Sniklas    along with GAS; see the file COPYING.  If not, write to the Free
200c6d0228Sniklas    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
210c6d0228Sniklas    02111-1307, USA.  */
222159047fSniklas 
23b55d4692Sfgsch /* Segments & sub-segments.  */
242159047fSniklas 
252159047fSniklas #include "as.h"
262159047fSniklas 
272159047fSniklas #include "subsegs.h"
282159047fSniklas #include "obstack.h"
292159047fSniklas 
302159047fSniklas frchainS *frchain_root, *frchain_now;
312159047fSniklas 
322159047fSniklas static struct obstack frchains;
332159047fSniklas 
342159047fSniklas #ifndef BFD_ASSEMBLER
352159047fSniklas #ifdef MANY_SEGMENTS
362159047fSniklas segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
372159047fSniklas 
382159047fSniklas #else
392159047fSniklas /* Commented in "subsegs.h".  */
402159047fSniklas frchainS *data0_frchainP, *bss0_frchainP;
412159047fSniklas 
422159047fSniklas #endif /* MANY_SEGMENTS */
43b55d4692Sfgsch char const *const seg_name[] = {
442159047fSniklas   "absolute",
452159047fSniklas #ifdef MANY_SEGMENTS
462159047fSniklas   "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9",
47191aa565Sniklas   "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19",
48191aa565Sniklas   "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29",
49191aa565Sniklas   "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39",
502159047fSniklas #else
512159047fSniklas   "text",
522159047fSniklas   "data",
532159047fSniklas   "bss",
542159047fSniklas #endif /* MANY_SEGMENTS */
552159047fSniklas   "unknown",
562159047fSniklas   "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
572159047fSniklas   "expr",
582159047fSniklas   "debug",
592159047fSniklas   "transfert vector preload",
602159047fSniklas   "transfert vector postload",
612159047fSniklas   "register",
622159047fSniklas   "",
632159047fSniklas };				/* Used by error reporters, dumpers etc.  */
642159047fSniklas #else /* BFD_ASSEMBLER */
652159047fSniklas 
662159047fSniklas /* Gas segment information for bfd_abs_section_ptr and
672159047fSniklas    bfd_und_section_ptr.  */
682159047fSniklas static segment_info_type *abs_seg_info;
692159047fSniklas static segment_info_type *und_seg_info;
702159047fSniklas 
712159047fSniklas #endif /* BFD_ASSEMBLER */
722159047fSniklas 
73*007c2a45Smiod static void subseg_set_rest (segT, subsegT);
742159047fSniklas 
752159047fSniklas static fragS dummy_frag;
762159047fSniklas 
772159047fSniklas static frchainS absolute_frchain;
782159047fSniklas 
792159047fSniklas void
subsegs_begin(void)80*007c2a45Smiod subsegs_begin (void)
812159047fSniklas {
822159047fSniklas   /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
832159047fSniklas #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
842159047fSniklas   know (SEG_ABSOLUTE == 0);
852159047fSniklas   know (SEG_TEXT == 1);
862159047fSniklas   know (SEG_DATA == 2);
872159047fSniklas   know (SEG_BSS == 3);
882159047fSniklas   know (SEG_UNKNOWN == 4);
892159047fSniklas   know (SEG_GOOF == 5);
902159047fSniklas   know (SEG_EXPR == 6);
912159047fSniklas   know (SEG_DEBUG == 7);
922159047fSniklas   know (SEG_NTV == 8);
932159047fSniklas   know (SEG_PTV == 9);
942159047fSniklas   know (SEG_REGISTER == 10);
952159047fSniklas   know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
962159047fSniklas #endif
972159047fSniklas 
982159047fSniklas   obstack_begin (&frchains, chunksize);
992159047fSniklas #if __GNUC__ >= 2
1002159047fSniklas   obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
1012159047fSniklas #endif
1022159047fSniklas 
1032159047fSniklas   frchain_root = NULL;
1042159047fSniklas   frchain_now = NULL;		/* Warn new_subseg() that we are booting.  */
1052159047fSniklas 
1062159047fSniklas   frag_now = &dummy_frag;
1072159047fSniklas 
1082159047fSniklas #ifndef BFD_ASSEMBLER
1092159047fSniklas   now_subseg = 42;		/* Lie for 1st call to subseg_new.  */
1102159047fSniklas #ifdef MANY_SEGMENTS
1112159047fSniklas   {
1122159047fSniklas     int i;
1132159047fSniklas     for (i = SEG_E0; i < SEG_UNKNOWN; i++)
1142159047fSniklas       {
1152159047fSniklas 	subseg_set (i, 0);
1162159047fSniklas 	segment_info[i].frchainP = frchain_now;
1172159047fSniklas       }
1182159047fSniklas   }
1192159047fSniklas #else
1202159047fSniklas   subseg_set (SEG_DATA, 0);	/* .data 0 */
1212159047fSniklas   data0_frchainP = frchain_now;
1222159047fSniklas 
1232159047fSniklas   subseg_set (SEG_BSS, 0);
1242159047fSniklas   bss0_frchainP = frchain_now;
1252159047fSniklas 
1262159047fSniklas #endif /* ! MANY_SEGMENTS */
1272159047fSniklas #endif /* ! BFD_ASSEMBLER */
1282159047fSniklas 
1292159047fSniklas   absolute_frchain.frch_seg = absolute_section;
1302159047fSniklas   absolute_frchain.frch_subseg = 0;
1312159047fSniklas #ifdef BFD_ASSEMBLER
1322159047fSniklas   absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
1332159047fSniklas #endif
1342159047fSniklas   absolute_frchain.frch_frag_now = &zero_address_frag;
1352159047fSniklas   absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
1362159047fSniklas }
1372159047fSniklas 
1382159047fSniklas /*
1392159047fSniklas  *			subseg_change()
1402159047fSniklas  *
1412159047fSniklas  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
1422159047fSniklas  * subsegment. If we are already in the correct subsegment, change nothing.
1432159047fSniklas  * This is used eg as a worker for subseg_set [which does make a new frag_now]
1442159047fSniklas  * and for changing segments after we have read the source. We construct eg
1452159047fSniklas  * fixSs even after the source file is read, so we do have to keep the
1462159047fSniklas  * segment context correct.
1472159047fSniklas  */
1482159047fSniklas void
subseg_change(register segT seg,register int subseg)149*007c2a45Smiod subseg_change (register segT seg, register int subseg)
1502159047fSniklas {
1512159047fSniklas   now_seg = seg;
1522159047fSniklas   now_subseg = subseg;
1532159047fSniklas 
1542159047fSniklas   if (now_seg == absolute_section)
1552159047fSniklas     return;
1562159047fSniklas 
1572159047fSniklas #ifdef BFD_ASSEMBLER
1582159047fSniklas   {
1592159047fSniklas     segment_info_type *seginfo;
1602159047fSniklas     seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
1612159047fSniklas     if (! seginfo)
1622159047fSniklas       {
1632159047fSniklas 	seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
1642159047fSniklas 	memset ((PTR) seginfo, 0, sizeof (*seginfo));
1652159047fSniklas 	seginfo->fix_root = NULL;
1662159047fSniklas 	seginfo->fix_tail = NULL;
1672159047fSniklas 	seginfo->bfd_section = seg;
1682159047fSniklas 	seginfo->sym = 0;
1692159047fSniklas 	if (seg == bfd_abs_section_ptr)
1702159047fSniklas 	  abs_seg_info = seginfo;
1712159047fSniklas 	else if (seg == bfd_und_section_ptr)
1722159047fSniklas 	  und_seg_info = seginfo;
1732159047fSniklas 	else
1742159047fSniklas 	  bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
1752159047fSniklas       }
1762159047fSniklas   }
1772159047fSniklas #else
1782159047fSniklas #ifdef MANY_SEGMENTS
1792159047fSniklas   seg_fix_rootP = &segment_info[seg].fix_root;
1802159047fSniklas   seg_fix_tailP = &segment_info[seg].fix_tail;
1812159047fSniklas #else
1822159047fSniklas   if (seg == SEG_DATA)
1832159047fSniklas     {
1842159047fSniklas       seg_fix_rootP = &data_fix_root;
1852159047fSniklas       seg_fix_tailP = &data_fix_tail;
1862159047fSniklas     }
1872159047fSniklas   else if (seg == SEG_TEXT)
1882159047fSniklas     {
1892159047fSniklas       seg_fix_rootP = &text_fix_root;
1902159047fSniklas       seg_fix_tailP = &text_fix_tail;
1912159047fSniklas     }
1922159047fSniklas   else
1932159047fSniklas     {
1942159047fSniklas       know (seg == SEG_BSS);
1952159047fSniklas       seg_fix_rootP = &bss_fix_root;
1962159047fSniklas       seg_fix_tailP = &bss_fix_tail;
1972159047fSniklas     }
1982159047fSniklas 
1992159047fSniklas #endif
2002159047fSniklas #endif
2012159047fSniklas }
2022159047fSniklas 
2032159047fSniklas static void
subseg_set_rest(segT seg,subsegT subseg)204*007c2a45Smiod subseg_set_rest (segT seg, subsegT subseg)
2052159047fSniklas {
2062159047fSniklas   register frchainS *frcP;	/* crawl frchain chain */
2072159047fSniklas   register frchainS **lastPP;	/* address of last pointer */
2082159047fSniklas   frchainS *newP;		/* address of new frchain */
2092159047fSniklas 
2102159047fSniklas   mri_common_symbol = NULL;
2112159047fSniklas 
2122159047fSniklas   if (frag_now && frchain_now)
2132159047fSniklas     frchain_now->frch_frag_now = frag_now;
2142159047fSniklas 
2152159047fSniklas   assert (frchain_now == 0
2162159047fSniklas 	  || now_seg == undefined_section
2172159047fSniklas 	  || now_seg == absolute_section
2182159047fSniklas 	  || frchain_now->frch_last == frag_now);
2192159047fSniklas 
2202159047fSniklas   subseg_change (seg, (int) subseg);
2212159047fSniklas 
2222159047fSniklas   if (seg == absolute_section)
2232159047fSniklas     {
2242159047fSniklas       frchain_now = &absolute_frchain;
2252159047fSniklas       frag_now = &zero_address_frag;
2262159047fSniklas       return;
2272159047fSniklas     }
2282159047fSniklas 
2292159047fSniklas   assert (frchain_now == 0
2302159047fSniklas 	  || now_seg == undefined_section
2312159047fSniklas 	  || frchain_now->frch_last == frag_now);
2322159047fSniklas 
2332159047fSniklas   /*
2342159047fSniklas    * Attempt to find or make a frchain for that sub seg.
2352159047fSniklas    * Crawl along chain of frchainSs, begins @ frchain_root.
2362159047fSniklas    * If we need to make a frchainS, link it into correct
2372159047fSniklas    * position of chain rooted in frchain_root.
2382159047fSniklas    */
2392159047fSniklas   for (frcP = *(lastPP = &frchain_root);
2402159047fSniklas        frcP && frcP->frch_seg <= seg;
2412159047fSniklas        frcP = *(lastPP = &frcP->frch_next))
2422159047fSniklas     {
2432159047fSniklas       if (frcP->frch_seg == seg
2442159047fSniklas 	  && frcP->frch_subseg >= subseg)
2452159047fSniklas 	{
2462159047fSniklas 	  break;
2472159047fSniklas 	}
2482159047fSniklas     }
2492159047fSniklas   /*
2502159047fSniklas    * frcP:		Address of the 1st frchainS in correct segment with
2512159047fSniklas    *		frch_subseg >= subseg.
2522159047fSniklas    *		We want to either use this frchainS, or we want
2532159047fSniklas    *		to insert a new frchainS just before it.
2542159047fSniklas    *
2552159047fSniklas    *		If frcP==NULL, then we are at the end of the chain
2562159047fSniklas    *		of frchainS-s. A NULL frcP means we fell off the end
2572159047fSniklas    *		of the chain looking for a
2582159047fSniklas    *		frch_subseg >= subseg, so we
2592159047fSniklas    *		must make a new frchainS.
2602159047fSniklas    *
2612159047fSniklas    *		If we ever maintain a pointer to
2622159047fSniklas    *		the last frchainS in the chain, we change that pointer
2632159047fSniklas    *		ONLY when frcP==NULL.
2642159047fSniklas    *
2652159047fSniklas    * lastPP:	Address of the pointer with value frcP;
2662159047fSniklas    *		Never NULL.
2672159047fSniklas    *		May point to frchain_root.
2682159047fSniklas    *
2692159047fSniklas    */
2702159047fSniklas   if (!frcP
2712159047fSniklas       || (frcP->frch_seg > seg
2722159047fSniklas 	  || frcP->frch_subseg > subseg))	/* Kinky logic only works with 2 segments.  */
2732159047fSniklas     {
2742159047fSniklas       /*
2752159047fSniklas        * This should be the only code that creates a frchainS.
2762159047fSniklas        */
2772159047fSniklas       newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
2782159047fSniklas       newP->frch_subseg = subseg;
2792159047fSniklas       newP->frch_seg = seg;
2802159047fSniklas #ifdef BFD_ASSEMBLER
2812159047fSniklas       newP->fix_root = NULL;
2822159047fSniklas       newP->fix_tail = NULL;
2832159047fSniklas #endif
284b305b0f1Sespie       obstack_begin (&newP->frch_obstack, chunksize);
2852159047fSniklas #if __GNUC__ >= 2
2862159047fSniklas       obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
2872159047fSniklas #endif
2882159047fSniklas       newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
2892159047fSniklas       newP->frch_frag_now->fr_type = rs_fill;
2902159047fSniklas 
2912159047fSniklas       newP->frch_root = newP->frch_last = newP->frch_frag_now;
2922159047fSniklas 
2932159047fSniklas       *lastPP = newP;
2942159047fSniklas       newP->frch_next = frcP;	/* perhaps NULL */
295b305b0f1Sespie 
296b305b0f1Sespie #ifdef BFD_ASSEMBLER
297b305b0f1Sespie       {
298b305b0f1Sespie 	segment_info_type *seginfo;
299b305b0f1Sespie 	seginfo = seg_info (seg);
300b305b0f1Sespie 	if (seginfo && seginfo->frchainP == frcP)
301b305b0f1Sespie 	  seginfo->frchainP = newP;
302b305b0f1Sespie       }
303b305b0f1Sespie #endif
304b305b0f1Sespie 
3052159047fSniklas       frcP = newP;
3062159047fSniklas     }
3072159047fSniklas   /*
3082159047fSniklas    * Here with frcP pointing to the frchainS for subseg.
3092159047fSniklas    */
3102159047fSniklas   frchain_now = frcP;
3112159047fSniklas   frag_now = frcP->frch_frag_now;
3122159047fSniklas 
3132159047fSniklas   assert (frchain_now->frch_last == frag_now);
3142159047fSniklas }
3152159047fSniklas 
3162159047fSniklas /*
3172159047fSniklas  *			subseg_set(segT, subsegT)
3182159047fSniklas  *
3192159047fSniklas  * If you attempt to change to the current subsegment, nothing happens.
3202159047fSniklas  *
3212159047fSniklas  * In:	segT, subsegT code for new subsegment.
3222159047fSniklas  *	frag_now -> incomplete frag for current subsegment.
3232159047fSniklas  *	If frag_now==NULL, then there is no old, incomplete frag, so
3242159047fSniklas  *	the old frag is not closed off.
3252159047fSniklas  *
3262159047fSniklas  * Out:	now_subseg, now_seg updated.
3272159047fSniklas  *	Frchain_now points to the (possibly new) struct frchain for this
3282159047fSniklas  *	sub-segment.
3292159047fSniklas  *	Frchain_root updated if needed.
3302159047fSniklas  */
3312159047fSniklas 
3322159047fSniklas #ifndef BFD_ASSEMBLER
3332159047fSniklas 
3342159047fSniklas segT
subseg_new(segname,subseg)3352159047fSniklas subseg_new (segname, subseg)
3362159047fSniklas      const char *segname;
3372159047fSniklas      subsegT subseg;
3382159047fSniklas {
3392159047fSniklas   int i;
3402159047fSniklas 
3412159047fSniklas   for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
3422159047fSniklas     {
3432159047fSniklas       const char *s;
3442159047fSniklas 
3452159047fSniklas       s = segment_name ((segT) i);
3462159047fSniklas       if (strcmp (segname, s) == 0
3472159047fSniklas 	  || (segname[0] == '.'
3482159047fSniklas 	      && strcmp (segname + 1, s) == 0))
3492159047fSniklas 	{
3502159047fSniklas 	  subseg_set ((segT) i, subseg);
3512159047fSniklas 	  return (segT) i;
3522159047fSniklas 	}
3532159047fSniklas #ifdef obj_segment_name
3542159047fSniklas       s = obj_segment_name ((segT) i);
3552159047fSniklas       if (strcmp (segname, s) == 0
3562159047fSniklas 	  || (segname[0] == '.'
3572159047fSniklas 	      && strcmp (segname + 1, s) == 0))
3582159047fSniklas 	{
3592159047fSniklas 	  subseg_set ((segT) i, subseg);
3602159047fSniklas 	  return (segT) i;
3612159047fSniklas 	}
3622159047fSniklas #endif
3632159047fSniklas     }
3642159047fSniklas 
3652159047fSniklas #ifdef obj_add_segment
3662159047fSniklas   {
3672159047fSniklas     segT new_seg;
3682159047fSniklas     new_seg = obj_add_segment (segname);
3692159047fSniklas     subseg_set (new_seg, subseg);
3702159047fSniklas     return new_seg;
3712159047fSniklas   }
3722159047fSniklas #else
373c074d1c9Sdrahn   as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname);
3742159047fSniklas   return now_seg;
3752159047fSniklas #endif
3762159047fSniklas }
3772159047fSniklas 
3782159047fSniklas void
subseg_set(seg,subseg)3792159047fSniklas subseg_set (seg, subseg)	/* begin assembly for a new sub-segment */
3802159047fSniklas      register segT seg;		/* SEG_DATA or SEG_TEXT */
3812159047fSniklas      register subsegT subseg;
3822159047fSniklas {
3832159047fSniklas #ifndef MANY_SEGMENTS
3842159047fSniklas   know (seg == SEG_DATA
3852159047fSniklas 	|| seg == SEG_TEXT
3862159047fSniklas 	|| seg == SEG_BSS
3872159047fSniklas 	|| seg == SEG_ABSOLUTE);
3882159047fSniklas #endif
3892159047fSniklas 
3902159047fSniklas   if (seg != now_seg || subseg != now_subseg)
3912159047fSniklas     {				/* we just changed sub-segments */
3922159047fSniklas       subseg_set_rest (seg, subseg);
3932159047fSniklas     }
3942159047fSniklas   mri_common_symbol = NULL;
3952159047fSniklas }
3962159047fSniklas 
3972159047fSniklas #else /* BFD_ASSEMBLER */
3982159047fSniklas 
3992159047fSniklas segT
subseg_get(const char * segname,int force_new)400*007c2a45Smiod subseg_get (const char *segname, int force_new)
4012159047fSniklas {
4022159047fSniklas   segT secptr;
4032159047fSniklas   segment_info_type *seginfo;
4042159047fSniklas   const char *now_seg_name = (now_seg
4052159047fSniklas 			      ? bfd_get_section_name (stdoutput, now_seg)
4062159047fSniklas 			      : 0);
4072159047fSniklas 
4082159047fSniklas   if (!force_new
4092159047fSniklas       && now_seg_name
4102159047fSniklas       && (now_seg_name == segname
4112159047fSniklas 	  || !strcmp (now_seg_name, segname)))
4122159047fSniklas     return now_seg;
4132159047fSniklas 
4142159047fSniklas   if (!force_new)
4152159047fSniklas     secptr = bfd_make_section_old_way (stdoutput, segname);
4162159047fSniklas   else
4172159047fSniklas     secptr = bfd_make_section_anyway (stdoutput, segname);
4182159047fSniklas 
419*007c2a45Smiod #ifdef obj_sec_set_private_data
420*007c2a45Smiod   obj_sec_set_private_data (stdoutput, secptr);
421*007c2a45Smiod #endif
422*007c2a45Smiod 
4232159047fSniklas   seginfo = seg_info (secptr);
4242159047fSniklas   if (! seginfo)
4252159047fSniklas     {
4262159047fSniklas       /* Check whether output_section is set first because secptr may
4272159047fSniklas 	 be bfd_abs_section_ptr.  */
4282159047fSniklas       if (secptr->output_section != secptr)
4292159047fSniklas 	secptr->output_section = secptr;
4302159047fSniklas       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
4312159047fSniklas       memset ((PTR) seginfo, 0, sizeof (*seginfo));
4322159047fSniklas       seginfo->fix_root = NULL;
4332159047fSniklas       seginfo->fix_tail = NULL;
4342159047fSniklas       seginfo->bfd_section = secptr;
4352159047fSniklas       if (secptr == bfd_abs_section_ptr)
4362159047fSniklas 	abs_seg_info = seginfo;
4372159047fSniklas       else if (secptr == bfd_und_section_ptr)
4382159047fSniklas 	und_seg_info = seginfo;
4392159047fSniklas       else
4402159047fSniklas 	bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
4412159047fSniklas       seginfo->frchainP = NULL;
4422159047fSniklas       seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
4432159047fSniklas       seginfo->sym = NULL;
4442159047fSniklas       seginfo->dot = NULL;
4452159047fSniklas     }
4462159047fSniklas   return secptr;
4472159047fSniklas }
4482159047fSniklas 
4492159047fSniklas segT
subseg_new(const char * segname,subsegT subseg)450*007c2a45Smiod subseg_new (const char *segname, subsegT subseg)
4512159047fSniklas {
4522159047fSniklas   segT secptr;
4532159047fSniklas   segment_info_type *seginfo;
4542159047fSniklas 
4552159047fSniklas   secptr = subseg_get (segname, 0);
4562159047fSniklas   subseg_set_rest (secptr, subseg);
4572159047fSniklas   seginfo = seg_info (secptr);
4582159047fSniklas   if (! seginfo->frchainP)
4592159047fSniklas     seginfo->frchainP = frchain_now;
4602159047fSniklas   return secptr;
4612159047fSniklas }
4622159047fSniklas 
4632159047fSniklas /* Like subseg_new, except a new section is always created, even if
4642159047fSniklas    a section with that name already exists.  */
4652159047fSniklas segT
subseg_force_new(const char * segname,subsegT subseg)466*007c2a45Smiod subseg_force_new (const char *segname, subsegT subseg)
4672159047fSniklas {
4682159047fSniklas   segT secptr;
4692159047fSniklas   segment_info_type *seginfo;
4702159047fSniklas 
4712159047fSniklas   secptr = subseg_get (segname, 1);
4722159047fSniklas   subseg_set_rest (secptr, subseg);
4732159047fSniklas   seginfo = seg_info (secptr);
4742159047fSniklas   if (! seginfo->frchainP)
4752159047fSniklas     seginfo->frchainP = frchain_now;
4762159047fSniklas   return secptr;
4772159047fSniklas }
4782159047fSniklas 
4792159047fSniklas void
subseg_set(segT secptr,subsegT subseg)480*007c2a45Smiod subseg_set (segT secptr, subsegT subseg)
4812159047fSniklas {
4822159047fSniklas   if (! (secptr == now_seg && subseg == now_subseg))
4832159047fSniklas     subseg_set_rest (secptr, subseg);
4842159047fSniklas   mri_common_symbol = NULL;
4852159047fSniklas }
4862159047fSniklas 
4872159047fSniklas #ifndef obj_sec_sym_ok_for_reloc
4882159047fSniklas #define obj_sec_sym_ok_for_reloc(SEC)	0
4892159047fSniklas #endif
4902159047fSniklas 
4912159047fSniklas /* Get the gas information we are storing for a section.  */
4922159047fSniklas 
4932159047fSniklas segment_info_type *
seg_info(segT sec)494*007c2a45Smiod seg_info (segT sec)
4952159047fSniklas {
4962159047fSniklas   if (sec == bfd_abs_section_ptr)
4972159047fSniklas     return abs_seg_info;
4982159047fSniklas   else if (sec == bfd_und_section_ptr)
4992159047fSniklas     return und_seg_info;
5002159047fSniklas   else
5012159047fSniklas     return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
5022159047fSniklas }
5032159047fSniklas 
5042159047fSniklas symbolS *
section_symbol(segT sec)505*007c2a45Smiod section_symbol (segT sec)
5062159047fSniklas {
5072159047fSniklas   segment_info_type *seginfo = seg_info (sec);
5082159047fSniklas   symbolS *s;
5092159047fSniklas 
5102159047fSniklas   if (seginfo == 0)
5112159047fSniklas     abort ();
5122159047fSniklas   if (seginfo->sym)
5132159047fSniklas     return seginfo->sym;
514191aa565Sniklas 
5152159047fSniklas #ifndef EMIT_SECTION_SYMBOLS
5162159047fSniklas #define EMIT_SECTION_SYMBOLS 1
5172159047fSniklas #endif
5182159047fSniklas 
519c074d1c9Sdrahn   if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
520b305b0f1Sespie     {
5212159047fSniklas       /* Here we know it won't be going into the symbol table.  */
522c074d1c9Sdrahn       s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
523b305b0f1Sespie     }
5242159047fSniklas   else
525b305b0f1Sespie     {
526c074d1c9Sdrahn       s = symbol_find_base (sec->symbol->name, 0);
527b305b0f1Sespie       if (s == NULL)
528c074d1c9Sdrahn 	s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
529b305b0f1Sespie       else
530b305b0f1Sespie 	{
531b305b0f1Sespie 	  if (S_GET_SEGMENT (s) == undefined_section)
532b305b0f1Sespie 	    {
533b305b0f1Sespie 	      S_SET_SEGMENT (s, sec);
534b305b0f1Sespie 	      symbol_set_frag (s, &zero_address_frag);
535b305b0f1Sespie 	    }
536b305b0f1Sespie 	}
537b305b0f1Sespie     }
538b305b0f1Sespie 
5392159047fSniklas   S_CLEAR_EXTERNAL (s);
5402159047fSniklas 
5412159047fSniklas   /* Use the BFD section symbol, if possible.  */
5422159047fSniklas   if (obj_sec_sym_ok_for_reloc (sec))
543b305b0f1Sespie     symbol_set_bfdsym (s, sec->symbol);
544c074d1c9Sdrahn   else
545c074d1c9Sdrahn     symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
546191aa565Sniklas 
5472159047fSniklas   seginfo->sym = s;
5482159047fSniklas   return s;
5492159047fSniklas }
5502159047fSniklas 
5512159047fSniklas #endif /* BFD_ASSEMBLER */
5522159047fSniklas 
553b305b0f1Sespie /* Return whether the specified segment is thought to hold text.  */
554b305b0f1Sespie 
555b305b0f1Sespie #ifndef BFD_ASSEMBLER
556b55d4692Sfgsch const char * const nontext_section_names[] = {
557b305b0f1Sespie   ".eh_frame",
558b305b0f1Sespie   ".gcc_except_table",
559b305b0f1Sespie #ifdef OBJ_COFF
560b305b0f1Sespie #ifndef COFF_LONG_SECTION_NAMES
561b305b0f1Sespie   ".eh_fram",
562b305b0f1Sespie   ".gcc_exc",
563b305b0f1Sespie #endif
564b305b0f1Sespie #endif
565b305b0f1Sespie   NULL
566b305b0f1Sespie };
567b305b0f1Sespie #endif /* ! BFD_ASSEMBLER */
568b305b0f1Sespie 
569b305b0f1Sespie int
subseg_text_p(segT sec)570*007c2a45Smiod subseg_text_p (segT sec)
571b305b0f1Sespie {
572b305b0f1Sespie #ifdef BFD_ASSEMBLER
573b305b0f1Sespie   return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
574b305b0f1Sespie #else /* ! BFD_ASSEMBLER */
575b305b0f1Sespie   const char * const *p;
576b305b0f1Sespie 
577c074d1c9Sdrahn   if (sec == data_section || sec == bss_section || sec == absolute_section)
578b305b0f1Sespie     return 0;
579b305b0f1Sespie 
580b305b0f1Sespie   for (p = nontext_section_names; *p != NULL; ++p)
581b305b0f1Sespie     {
582b305b0f1Sespie       if (strcmp (segment_name (sec), *p) == 0)
583b305b0f1Sespie 	return 0;
584b305b0f1Sespie 
585b305b0f1Sespie #ifdef obj_segment_name
586b305b0f1Sespie       if (strcmp (obj_segment_name (sec), *p) == 0)
587b305b0f1Sespie 	return 0;
588b305b0f1Sespie #endif
589b305b0f1Sespie     }
590b305b0f1Sespie 
591b305b0f1Sespie   return 1;
592b305b0f1Sespie 
593b305b0f1Sespie #endif /* ! BFD_ASSEMBLER */
594b305b0f1Sespie }
595b305b0f1Sespie 
596191aa565Sniklas void
subsegs_print_statistics(FILE * file)597*007c2a45Smiod subsegs_print_statistics (FILE *file)
598191aa565Sniklas {
599191aa565Sniklas   frchainS *frchp;
600191aa565Sniklas   fprintf (file, "frag chains:\n");
601191aa565Sniklas   for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
602191aa565Sniklas     {
603191aa565Sniklas       int count = 0;
604191aa565Sniklas       fragS *fragp;
605191aa565Sniklas 
606191aa565Sniklas       /* If frch_subseg is non-zero, it's probably been chained onto
607191aa565Sniklas 	 the end of a previous subsection.  Don't count it again.  */
608191aa565Sniklas       if (frchp->frch_subseg != 0)
609191aa565Sniklas 	continue;
610191aa565Sniklas 
611191aa565Sniklas       /* Skip gas-internal sections.  */
612191aa565Sniklas       if (segment_name (frchp->frch_seg)[0] == '*')
613191aa565Sniklas 	continue;
614191aa565Sniklas 
615191aa565Sniklas       for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
616191aa565Sniklas 	{
617191aa565Sniklas #if 0
618191aa565Sniklas 	  switch (fragp->fr_type)
619191aa565Sniklas 	    {
620191aa565Sniklas 	    case rs_fill:
621191aa565Sniklas 	      fprintf (file, "f"); break;
622191aa565Sniklas 	    case rs_align:
623191aa565Sniklas 	      fprintf (file, "a"); break;
624191aa565Sniklas 	    case rs_align_code:
625191aa565Sniklas 	      fprintf (file, "c"); break;
626191aa565Sniklas 	    case rs_org:
627191aa565Sniklas 	      fprintf (file, "o"); break;
628191aa565Sniklas 	    case rs_machine_dependent:
629191aa565Sniklas 	      fprintf (file, "m"); break;
630191aa565Sniklas 	    case rs_space:
631191aa565Sniklas 	      fprintf (file, "s"); break;
632191aa565Sniklas 	    case 0:
633191aa565Sniklas 	      fprintf (file, "0"); break;
634191aa565Sniklas 	    default:
635191aa565Sniklas 	      fprintf (file, "?"); break;
636191aa565Sniklas 	    }
637191aa565Sniklas #endif
638191aa565Sniklas 	  count++;
639191aa565Sniklas 	}
640191aa565Sniklas       fprintf (file, "\n");
641c074d1c9Sdrahn       fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
642191aa565Sniklas 	       segment_name (frchp->frch_seg), count);
643191aa565Sniklas     }
644191aa565Sniklas }
645191aa565Sniklas 
6462159047fSniklas /* end of subsegs.c */
647