133965Sjdp/* subsegs.c - subsegments -
278828Sobrien   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3218822Sdim   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
433965Sjdp   Free Software Foundation, Inc.
533965Sjdp
633965Sjdp   This file is part of GAS, the GNU Assembler.
733965Sjdp
833965Sjdp   GAS is free software; you can redistribute it and/or modify
933965Sjdp   it under the terms of the GNU General Public License as published by
1033965Sjdp   the Free Software Foundation; either version 2, or (at your option)
1133965Sjdp   any later version.
1233965Sjdp
1333965Sjdp   GAS is distributed in the hope that it will be useful,
1433965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1533965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1633965Sjdp   GNU General Public License for more details.
1733965Sjdp
1833965Sjdp   You should have received a copy of the GNU General Public License
1933965Sjdp   along with GAS; see the file COPYING.  If not, write to the Free
20218822Sdim   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2233965Sjdp
2377298Sobrien/* Segments & sub-segments.  */
2433965Sjdp
2533965Sjdp#include "as.h"
2633965Sjdp
2733965Sjdp#include "subsegs.h"
2833965Sjdp#include "obstack.h"
2933965Sjdp
30218822SdimfrchainS *frchain_now;
3133965Sjdp
3233965Sjdpstatic struct obstack frchains;
3333965Sjdp
3433965Sjdpstatic fragS dummy_frag;
3533965Sjdp
3633965Sjdp
3733965Sjdpvoid
38130561Sobriensubsegs_begin (void)
3933965Sjdp{
4033965Sjdp  obstack_begin (&frchains, chunksize);
4133965Sjdp#if __GNUC__ >= 2
4233965Sjdp  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
4333965Sjdp#endif
4433965Sjdp
4577298Sobrien  frchain_now = NULL;		/* Warn new_subseg() that we are booting.  */
4633965Sjdp  frag_now = &dummy_frag;
4733965Sjdp}
4833965Sjdp
4933965Sjdp/*
5033965Sjdp *			subseg_change()
5133965Sjdp *
5233965Sjdp * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
5333965Sjdp * subsegment. If we are already in the correct subsegment, change nothing.
5433965Sjdp * This is used eg as a worker for subseg_set [which does make a new frag_now]
5533965Sjdp * and for changing segments after we have read the source. We construct eg
5633965Sjdp * fixSs even after the source file is read, so we do have to keep the
5733965Sjdp * segment context correct.
5833965Sjdp */
5933965Sjdpvoid
60130561Sobriensubseg_change (register segT seg, register int subseg)
6133965Sjdp{
62218822Sdim  segment_info_type *seginfo = seg_info (seg);
6333965Sjdp  now_seg = seg;
6433965Sjdp  now_subseg = subseg;
6533965Sjdp
66218822Sdim  if (! seginfo)
6733965Sjdp    {
68218822Sdim      seginfo = xcalloc (1, sizeof (*seginfo));
69218822Sdim      seginfo->bfd_section = seg;
70223262Sbenl      (void) bfd_set_section_userdata (stdoutput, seg, seginfo);
7133965Sjdp    }
7233965Sjdp}
7333965Sjdp
7433965Sjdpstatic void
75130561Sobriensubseg_set_rest (segT seg, subsegT subseg)
7633965Sjdp{
77218822Sdim  frchainS *frcP;		/* crawl frchain chain */
78218822Sdim  frchainS **lastPP;		/* address of last pointer */
7933965Sjdp  frchainS *newP;		/* address of new frchain */
80218822Sdim  segment_info_type *seginfo;
8133965Sjdp
8233965Sjdp  mri_common_symbol = NULL;
8333965Sjdp
8433965Sjdp  if (frag_now && frchain_now)
8533965Sjdp    frchain_now->frch_frag_now = frag_now;
8633965Sjdp
8733965Sjdp  assert (frchain_now == 0
8833965Sjdp	  || frchain_now->frch_last == frag_now);
8933965Sjdp
9033965Sjdp  subseg_change (seg, (int) subseg);
9133965Sjdp
92218822Sdim  seginfo = seg_info (seg);
9333965Sjdp
94218822Sdim  /* Attempt to find or make a frchain for that subsection.
95218822Sdim     We keep the list sorted by subsection number.  */
96218822Sdim  for (frcP = *(lastPP = &seginfo->frchainP);
97218822Sdim       frcP != NULL;
98218822Sdim       frcP = *(lastPP = &frcP->frch_next))
99218822Sdim    if (frcP->frch_subseg >= subseg)
100218822Sdim      break;
10133965Sjdp
102218822Sdim  if (frcP == NULL || frcP->frch_subseg != subseg)
10333965Sjdp    {
104218822Sdim      /* This should be the only code that creates a frchainS.  */
105218822Sdim
106218822Sdim      newP = obstack_alloc (&frchains, sizeof (frchainS));
10733965Sjdp      newP->frch_subseg = subseg;
10833965Sjdp      newP->fix_root = NULL;
10933965Sjdp      newP->fix_tail = NULL;
11038889Sjdp      obstack_begin (&newP->frch_obstack, chunksize);
11133965Sjdp#if __GNUC__ >= 2
11233965Sjdp      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
11333965Sjdp#endif
11433965Sjdp      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
11533965Sjdp      newP->frch_frag_now->fr_type = rs_fill;
116218822Sdim      newP->frch_cfi_data = NULL;
11733965Sjdp
11833965Sjdp      newP->frch_root = newP->frch_last = newP->frch_frag_now;
11933965Sjdp
12033965Sjdp      *lastPP = newP;
121218822Sdim      newP->frch_next = frcP;
12233965Sjdp      frcP = newP;
12333965Sjdp    }
124218822Sdim
12533965Sjdp  frchain_now = frcP;
12633965Sjdp  frag_now = frcP->frch_frag_now;
12733965Sjdp
12833965Sjdp  assert (frchain_now->frch_last == frag_now);
12933965Sjdp}
13033965Sjdp
13133965Sjdp/*
13233965Sjdp *			subseg_set(segT, subsegT)
13333965Sjdp *
13433965Sjdp * If you attempt to change to the current subsegment, nothing happens.
13533965Sjdp *
13633965Sjdp * In:	segT, subsegT code for new subsegment.
13733965Sjdp *	frag_now -> incomplete frag for current subsegment.
13833965Sjdp *	If frag_now==NULL, then there is no old, incomplete frag, so
13933965Sjdp *	the old frag is not closed off.
14033965Sjdp *
14133965Sjdp * Out:	now_subseg, now_seg updated.
14233965Sjdp *	Frchain_now points to the (possibly new) struct frchain for this
14333965Sjdp *	sub-segment.
14433965Sjdp */
14533965Sjdp
14633965SjdpsegT
147130561Sobriensubseg_get (const char *segname, int force_new)
14833965Sjdp{
14933965Sjdp  segT secptr;
15033965Sjdp  segment_info_type *seginfo;
15133965Sjdp  const char *now_seg_name = (now_seg
15233965Sjdp			      ? bfd_get_section_name (stdoutput, now_seg)
15333965Sjdp			      : 0);
15433965Sjdp
15533965Sjdp  if (!force_new
15633965Sjdp      && now_seg_name
15733965Sjdp      && (now_seg_name == segname
15833965Sjdp	  || !strcmp (now_seg_name, segname)))
15933965Sjdp    return now_seg;
16033965Sjdp
16133965Sjdp  if (!force_new)
16233965Sjdp    secptr = bfd_make_section_old_way (stdoutput, segname);
16333965Sjdp  else
16433965Sjdp    secptr = bfd_make_section_anyway (stdoutput, segname);
16533965Sjdp
16633965Sjdp  seginfo = seg_info (secptr);
16733965Sjdp  if (! seginfo)
16833965Sjdp    {
169218822Sdim      secptr->output_section = secptr;
170218822Sdim      seginfo = xcalloc (1, sizeof (*seginfo));
17133965Sjdp      seginfo->bfd_section = secptr;
172223262Sbenl      (void) bfd_set_section_userdata (stdoutput, secptr, seginfo);
17333965Sjdp    }
17433965Sjdp  return secptr;
17533965Sjdp}
17633965Sjdp
17733965SjdpsegT
178130561Sobriensubseg_new (const char *segname, subsegT subseg)
17933965Sjdp{
18033965Sjdp  segT secptr;
18133965Sjdp
18233965Sjdp  secptr = subseg_get (segname, 0);
18333965Sjdp  subseg_set_rest (secptr, subseg);
18433965Sjdp  return secptr;
18533965Sjdp}
18633965Sjdp
18733965Sjdp/* Like subseg_new, except a new section is always created, even if
18833965Sjdp   a section with that name already exists.  */
18933965SjdpsegT
190130561Sobriensubseg_force_new (const char *segname, subsegT subseg)
19133965Sjdp{
19233965Sjdp  segT secptr;
19333965Sjdp
19433965Sjdp  secptr = subseg_get (segname, 1);
19533965Sjdp  subseg_set_rest (secptr, subseg);
19633965Sjdp  return secptr;
19733965Sjdp}
19833965Sjdp
19933965Sjdpvoid
200130561Sobriensubseg_set (segT secptr, subsegT subseg)
20133965Sjdp{
20233965Sjdp  if (! (secptr == now_seg && subseg == now_subseg))
20333965Sjdp    subseg_set_rest (secptr, subseg);
20433965Sjdp  mri_common_symbol = NULL;
20533965Sjdp}
20633965Sjdp
20733965Sjdp#ifndef obj_sec_sym_ok_for_reloc
20833965Sjdp#define obj_sec_sym_ok_for_reloc(SEC)	0
20933965Sjdp#endif
21033965Sjdp
21133965SjdpsymbolS *
212130561Sobriensection_symbol (segT sec)
21333965Sjdp{
21433965Sjdp  segment_info_type *seginfo = seg_info (sec);
21533965Sjdp  symbolS *s;
21633965Sjdp
21733965Sjdp  if (seginfo == 0)
21833965Sjdp    abort ();
21933965Sjdp  if (seginfo->sym)
22033965Sjdp    return seginfo->sym;
22133965Sjdp
22233965Sjdp#ifndef EMIT_SECTION_SYMBOLS
22333965Sjdp#define EMIT_SECTION_SYMBOLS 1
22433965Sjdp#endif
22533965Sjdp
226130561Sobrien  if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
22760484Sobrien    {
22860484Sobrien      /* Here we know it won't be going into the symbol table.  */
229130561Sobrien      s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
23060484Sobrien    }
23133965Sjdp  else
23260484Sobrien    {
233218822Sdim      segT seg;
234218822Sdim      s = symbol_find (sec->symbol->name);
235218822Sdim      /* We have to make sure it is the right symbol when we
236218822Sdim	 have multiple sections with the same section name.  */
237218822Sdim      if (s == NULL
238218822Sdim	  || ((seg = S_GET_SEGMENT (s)) != sec
239218822Sdim	      && seg != undefined_section))
240130561Sobrien	s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
241218822Sdim      else if (seg == undefined_section)
24260484Sobrien	{
243218822Sdim	  S_SET_SEGMENT (s, sec);
244218822Sdim	  symbol_set_frag (s, &zero_address_frag);
24560484Sobrien	}
24660484Sobrien    }
24760484Sobrien
24833965Sjdp  S_CLEAR_EXTERNAL (s);
24933965Sjdp
25033965Sjdp  /* Use the BFD section symbol, if possible.  */
25133965Sjdp  if (obj_sec_sym_ok_for_reloc (sec))
25260484Sobrien    symbol_set_bfdsym (s, sec->symbol);
253130561Sobrien  else
254130561Sobrien    symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
25533965Sjdp
25633965Sjdp  seginfo->sym = s;
25733965Sjdp  return s;
25833965Sjdp}
25933965Sjdp
26060484Sobrien/* Return whether the specified segment is thought to hold text.  */
26160484Sobrien
26260484Sobrienint
263130561Sobriensubseg_text_p (segT sec)
26460484Sobrien{
26560484Sobrien  return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
266218822Sdim}
26760484Sobrien
268218822Sdim/* Return non zero if SEC has at least one byte of data.  It is
269218822Sdim   possible that we'll return zero even on a non-empty section because
270218822Sdim   we don't know all the fragment types, and it is possible that an
271218822Sdim   fr_fix == 0 one still contributes data.  Think of this as
272218822Sdim   seg_definitely_not_empty_p.  */
273218822Sdim
274218822Sdimint
275218822Sdimseg_not_empty_p (segT sec ATTRIBUTE_UNUSED)
276218822Sdim{
277218822Sdim  segment_info_type *seginfo = seg_info (sec);
278218822Sdim  frchainS *chain;
279218822Sdim  fragS *frag;
280218822Sdim
281218822Sdim  if (!seginfo)
28260484Sobrien    return 0;
283218822Sdim
284218822Sdim  for (chain = seginfo->frchainP; chain; chain = chain->frch_next)
28560484Sobrien    {
286218822Sdim      for (frag = chain->frch_root; frag; frag = frag->fr_next)
287218822Sdim	if (frag->fr_fix)
288218822Sdim	  return 1;
289218822Sdim      if (obstack_next_free (&chain->frch_obstack)
290218822Sdim	  != chain->frch_last->fr_literal)
291218822Sdim	return 1;
29260484Sobrien    }
293218822Sdim  return 0;
29460484Sobrien}
29560484Sobrien
29633965Sjdpvoid
297130561Sobriensubsegs_print_statistics (FILE *file)
29833965Sjdp{
29933965Sjdp  frchainS *frchp;
300218822Sdim  asection *s;
301218822Sdim
30233965Sjdp  fprintf (file, "frag chains:\n");
303218822Sdim  for (s = stdoutput->sections; s; s = s->next)
30433965Sjdp    {
305218822Sdim      segment_info_type *seginfo;
30633965Sjdp
307218822Sdim      /* Skip gas-internal sections.  */
308218822Sdim      if (segment_name (s)[0] == '*')
30933965Sjdp	continue;
31033965Sjdp
311218822Sdim      seginfo = seg_info (s);
312218822Sdim      if (!seginfo)
31333965Sjdp	continue;
31433965Sjdp
315218822Sdim      for (frchp = seginfo->frchainP; frchp; frchp = frchp->frch_next)
31633965Sjdp	{
317218822Sdim	  int count = 0;
318218822Sdim	  fragS *fragp;
319218822Sdim
320218822Sdim	  for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
321218822Sdim	    count++;
322218822Sdim
323218822Sdim	  fprintf (file, "\n");
324218822Sdim	  fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
325218822Sdim		   segment_name (s), count);
32633965Sjdp	}
32733965Sjdp    }
32833965Sjdp}
32933965Sjdp
33033965Sjdp/* end of subsegs.c */
331