1/* subsegs.c - subsegments -
2   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
4   Free Software Foundation, Inc.
5
6   This file is part of GAS, the GNU Assembler.
7
8   GAS is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   GAS is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with GAS; see the file COPYING.  If not, write to the Free
20   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21   02110-1301, USA.  */
22
23/* Segments & sub-segments.  */
24
25#include "as.h"
26
27#include "subsegs.h"
28#include "obstack.h"
29
30frchainS *frchain_now;
31
32static struct obstack frchains;
33
34static fragS dummy_frag;
35
36
37void
38subsegs_begin (void)
39{
40  obstack_begin (&frchains, chunksize);
41#if __GNUC__ >= 2
42  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
43#endif
44
45  frchain_now = NULL;		/* Warn new_subseg() that we are booting.  */
46  frag_now = &dummy_frag;
47}
48
49/*
50 *			subseg_change()
51 *
52 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
53 * subsegment. If we are already in the correct subsegment, change nothing.
54 * This is used eg as a worker for subseg_set [which does make a new frag_now]
55 * and for changing segments after we have read the source. We construct eg
56 * fixSs even after the source file is read, so we do have to keep the
57 * segment context correct.
58 */
59void
60subseg_change (register segT seg, register int subseg)
61{
62  segment_info_type *seginfo = seg_info (seg);
63  now_seg = seg;
64  now_subseg = subseg;
65
66  if (! seginfo)
67    {
68      seginfo = xcalloc (1, sizeof (*seginfo));
69      seginfo->bfd_section = seg;
70      (void) bfd_set_section_userdata (stdoutput, seg, seginfo);
71    }
72}
73
74static void
75subseg_set_rest (segT seg, subsegT subseg)
76{
77  frchainS *frcP;		/* crawl frchain chain */
78  frchainS **lastPP;		/* address of last pointer */
79  frchainS *newP;		/* address of new frchain */
80  segment_info_type *seginfo;
81
82  mri_common_symbol = NULL;
83
84  if (frag_now && frchain_now)
85    frchain_now->frch_frag_now = frag_now;
86
87  assert (frchain_now == 0
88	  || frchain_now->frch_last == frag_now);
89
90  subseg_change (seg, (int) subseg);
91
92  seginfo = seg_info (seg);
93
94  /* Attempt to find or make a frchain for that subsection.
95     We keep the list sorted by subsection number.  */
96  for (frcP = *(lastPP = &seginfo->frchainP);
97       frcP != NULL;
98       frcP = *(lastPP = &frcP->frch_next))
99    if (frcP->frch_subseg >= subseg)
100      break;
101
102  if (frcP == NULL || frcP->frch_subseg != subseg)
103    {
104      /* This should be the only code that creates a frchainS.  */
105
106      newP = obstack_alloc (&frchains, sizeof (frchainS));
107      newP->frch_subseg = subseg;
108      newP->fix_root = NULL;
109      newP->fix_tail = NULL;
110      obstack_begin (&newP->frch_obstack, chunksize);
111#if __GNUC__ >= 2
112      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
113#endif
114      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
115      newP->frch_frag_now->fr_type = rs_fill;
116      newP->frch_cfi_data = NULL;
117
118      newP->frch_root = newP->frch_last = newP->frch_frag_now;
119
120      *lastPP = newP;
121      newP->frch_next = frcP;
122      frcP = newP;
123    }
124
125  frchain_now = frcP;
126  frag_now = frcP->frch_frag_now;
127
128  assert (frchain_now->frch_last == frag_now);
129}
130
131/*
132 *			subseg_set(segT, subsegT)
133 *
134 * If you attempt to change to the current subsegment, nothing happens.
135 *
136 * In:	segT, subsegT code for new subsegment.
137 *	frag_now -> incomplete frag for current subsegment.
138 *	If frag_now==NULL, then there is no old, incomplete frag, so
139 *	the old frag is not closed off.
140 *
141 * Out:	now_subseg, now_seg updated.
142 *	Frchain_now points to the (possibly new) struct frchain for this
143 *	sub-segment.
144 */
145
146segT
147subseg_get (const char *segname, int force_new)
148{
149  segT secptr;
150  segment_info_type *seginfo;
151  const char *now_seg_name = (now_seg
152			      ? bfd_get_section_name (stdoutput, now_seg)
153			      : 0);
154
155  if (!force_new
156      && now_seg_name
157      && (now_seg_name == segname
158	  || !strcmp (now_seg_name, segname)))
159    return now_seg;
160
161  if (!force_new)
162    secptr = bfd_make_section_old_way (stdoutput, segname);
163  else
164    secptr = bfd_make_section_anyway (stdoutput, segname);
165
166  seginfo = seg_info (secptr);
167  if (! seginfo)
168    {
169      secptr->output_section = secptr;
170      seginfo = xcalloc (1, sizeof (*seginfo));
171      seginfo->bfd_section = secptr;
172      (void) bfd_set_section_userdata (stdoutput, secptr, seginfo);
173    }
174  return secptr;
175}
176
177segT
178subseg_new (const char *segname, subsegT subseg)
179{
180  segT secptr;
181
182  secptr = subseg_get (segname, 0);
183  subseg_set_rest (secptr, subseg);
184  return secptr;
185}
186
187/* Like subseg_new, except a new section is always created, even if
188   a section with that name already exists.  */
189segT
190subseg_force_new (const char *segname, subsegT subseg)
191{
192  segT secptr;
193
194  secptr = subseg_get (segname, 1);
195  subseg_set_rest (secptr, subseg);
196  return secptr;
197}
198
199void
200subseg_set (segT secptr, subsegT subseg)
201{
202  if (! (secptr == now_seg && subseg == now_subseg))
203    subseg_set_rest (secptr, subseg);
204  mri_common_symbol = NULL;
205}
206
207#ifndef obj_sec_sym_ok_for_reloc
208#define obj_sec_sym_ok_for_reloc(SEC)	0
209#endif
210
211symbolS *
212section_symbol (segT sec)
213{
214  segment_info_type *seginfo = seg_info (sec);
215  symbolS *s;
216
217  if (seginfo == 0)
218    abort ();
219  if (seginfo->sym)
220    return seginfo->sym;
221
222#ifndef EMIT_SECTION_SYMBOLS
223#define EMIT_SECTION_SYMBOLS 1
224#endif
225
226  if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
227    {
228      /* Here we know it won't be going into the symbol table.  */
229      s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
230    }
231  else
232    {
233      segT seg;
234      s = symbol_find (sec->symbol->name);
235      /* We have to make sure it is the right symbol when we
236	 have multiple sections with the same section name.  */
237      if (s == NULL
238	  || ((seg = S_GET_SEGMENT (s)) != sec
239	      && seg != undefined_section))
240	s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
241      else if (seg == undefined_section)
242	{
243	  S_SET_SEGMENT (s, sec);
244	  symbol_set_frag (s, &zero_address_frag);
245	}
246    }
247
248  S_CLEAR_EXTERNAL (s);
249
250  /* Use the BFD section symbol, if possible.  */
251  if (obj_sec_sym_ok_for_reloc (sec))
252    symbol_set_bfdsym (s, sec->symbol);
253  else
254    symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
255
256  seginfo->sym = s;
257  return s;
258}
259
260/* Return whether the specified segment is thought to hold text.  */
261
262int
263subseg_text_p (segT sec)
264{
265  return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
266}
267
268/* Return non zero if SEC has at least one byte of data.  It is
269   possible that we'll return zero even on a non-empty section because
270   we don't know all the fragment types, and it is possible that an
271   fr_fix == 0 one still contributes data.  Think of this as
272   seg_definitely_not_empty_p.  */
273
274int
275seg_not_empty_p (segT sec ATTRIBUTE_UNUSED)
276{
277  segment_info_type *seginfo = seg_info (sec);
278  frchainS *chain;
279  fragS *frag;
280
281  if (!seginfo)
282    return 0;
283
284  for (chain = seginfo->frchainP; chain; chain = chain->frch_next)
285    {
286      for (frag = chain->frch_root; frag; frag = frag->fr_next)
287	if (frag->fr_fix)
288	  return 1;
289      if (obstack_next_free (&chain->frch_obstack)
290	  != chain->frch_last->fr_literal)
291	return 1;
292    }
293  return 0;
294}
295
296void
297subsegs_print_statistics (FILE *file)
298{
299  frchainS *frchp;
300  asection *s;
301
302  fprintf (file, "frag chains:\n");
303  for (s = stdoutput->sections; s; s = s->next)
304    {
305      segment_info_type *seginfo;
306
307      /* Skip gas-internal sections.  */
308      if (segment_name (s)[0] == '*')
309	continue;
310
311      seginfo = seg_info (s);
312      if (!seginfo)
313	continue;
314
315      for (frchp = seginfo->frchainP; frchp; frchp = frchp->frch_next)
316	{
317	  int count = 0;
318	  fragS *fragp;
319
320	  for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
321	    count++;
322
323	  fprintf (file, "\n");
324	  fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
325		   segment_name (s), count);
326	}
327    }
328}
329
330/* end of subsegs.c */
331