subsegs.c revision 1.3
1/* subsegs.c - subsegments -
2   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 1996
3   Free Software Foundation, Inc.
4
5   This file is part of GAS, the GNU Assembler.
6
7   GAS is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11
12   GAS is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with GAS; see the file COPYING.  If not, write to the Free
19   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20   02111-1307, USA.  */
21
22/*
23 * Segments & sub-segments.
24 */
25
26#include "as.h"
27
28#include "subsegs.h"
29#include "obstack.h"
30
31frchainS *frchain_root, *frchain_now;
32
33static struct obstack frchains;
34
35#ifndef BFD_ASSEMBLER
36#ifdef MANY_SEGMENTS
37segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
38
39#else
40/* Commented in "subsegs.h". */
41frchainS *data0_frchainP, *bss0_frchainP;
42
43#endif /* MANY_SEGMENTS */
44char const *const seg_name[] =
45{
46  "absolute",
47#ifdef MANY_SEGMENTS
48  "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9",
49  "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19",
50  "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29",
51  "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39",
52#else
53  "text",
54  "data",
55  "bss",
56#endif /* MANY_SEGMENTS */
57  "unknown",
58  "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
59  "expr",
60  "debug",
61  "transfert vector preload",
62  "transfert vector postload",
63  "register",
64  "",
65};				/* Used by error reporters, dumpers etc. */
66#else /* BFD_ASSEMBLER */
67
68/* Gas segment information for bfd_abs_section_ptr and
69   bfd_und_section_ptr.  */
70static segment_info_type *abs_seg_info;
71static segment_info_type *und_seg_info;
72
73#endif /* BFD_ASSEMBLER */
74
75static void subseg_set_rest PARAMS ((segT, subsegT));
76
77static fragS dummy_frag;
78
79static frchainS absolute_frchain;
80
81void
82subsegs_begin ()
83{
84  /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
85#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
86  know (SEG_ABSOLUTE == 0);
87  know (SEG_TEXT == 1);
88  know (SEG_DATA == 2);
89  know (SEG_BSS == 3);
90  know (SEG_UNKNOWN == 4);
91  know (SEG_GOOF == 5);
92  know (SEG_EXPR == 6);
93  know (SEG_DEBUG == 7);
94  know (SEG_NTV == 8);
95  know (SEG_PTV == 9);
96  know (SEG_REGISTER == 10);
97  know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
98#endif
99
100  obstack_begin (&frchains, chunksize);
101#if __GNUC__ >= 2
102  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
103#endif
104
105  frchain_root = NULL;
106  frchain_now = NULL;		/* Warn new_subseg() that we are booting. */
107
108  frag_now = &dummy_frag;
109
110#ifndef BFD_ASSEMBLER
111  now_subseg = 42;		/* Lie for 1st call to subseg_new. */
112#ifdef MANY_SEGMENTS
113  {
114    int i;
115    for (i = SEG_E0; i < SEG_UNKNOWN; i++)
116      {
117	subseg_set (i, 0);
118	segment_info[i].frchainP = frchain_now;
119      }
120  }
121#else
122  subseg_set (SEG_DATA, 0);	/* .data 0 */
123  data0_frchainP = frchain_now;
124
125  subseg_set (SEG_BSS, 0);
126  bss0_frchainP = frchain_now;
127
128#endif /* ! MANY_SEGMENTS */
129#endif /* ! BFD_ASSEMBLER */
130
131  absolute_frchain.frch_seg = absolute_section;
132  absolute_frchain.frch_subseg = 0;
133#ifdef BFD_ASSEMBLER
134  absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
135#endif
136  absolute_frchain.frch_frag_now = &zero_address_frag;
137  absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
138}
139
140/*
141 *			subseg_change()
142 *
143 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
144 * subsegment. If we are already in the correct subsegment, change nothing.
145 * This is used eg as a worker for subseg_set [which does make a new frag_now]
146 * and for changing segments after we have read the source. We construct eg
147 * fixSs even after the source file is read, so we do have to keep the
148 * segment context correct.
149 */
150void
151subseg_change (seg, subseg)
152     register segT seg;
153     register int subseg;
154{
155  now_seg = seg;
156  now_subseg = subseg;
157
158  if (now_seg == absolute_section)
159    return;
160
161#ifdef BFD_ASSEMBLER
162  {
163    segment_info_type *seginfo;
164    seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
165    if (! seginfo)
166      {
167	seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
168	memset ((PTR) seginfo, 0, sizeof (*seginfo));
169	seginfo->fix_root = NULL;
170	seginfo->fix_tail = NULL;
171	seginfo->bfd_section = seg;
172	seginfo->sym = 0;
173	if (seg == bfd_abs_section_ptr)
174	  abs_seg_info = seginfo;
175	else if (seg == bfd_und_section_ptr)
176	  und_seg_info = seginfo;
177	else
178	  bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
179      }
180  }
181#else
182#ifdef MANY_SEGMENTS
183  seg_fix_rootP = &segment_info[seg].fix_root;
184  seg_fix_tailP = &segment_info[seg].fix_tail;
185#else
186  if (seg == SEG_DATA)
187    {
188      seg_fix_rootP = &data_fix_root;
189      seg_fix_tailP = &data_fix_tail;
190    }
191  else if (seg == SEG_TEXT)
192    {
193      seg_fix_rootP = &text_fix_root;
194      seg_fix_tailP = &text_fix_tail;
195    }
196  else
197    {
198      know (seg == SEG_BSS);
199      seg_fix_rootP = &bss_fix_root;
200      seg_fix_tailP = &bss_fix_tail;
201    }
202
203#endif
204#endif
205}
206
207static void
208subseg_set_rest (seg, subseg)
209     segT seg;
210     subsegT subseg;
211{
212  register frchainS *frcP;	/* crawl frchain chain */
213  register frchainS **lastPP;	/* address of last pointer */
214  frchainS *newP;		/* address of new frchain */
215
216  mri_common_symbol = NULL;
217
218  if (frag_now && frchain_now)
219    frchain_now->frch_frag_now = frag_now;
220
221  assert (frchain_now == 0
222	  || now_seg == undefined_section
223	  || now_seg == absolute_section
224	  || frchain_now->frch_last == frag_now);
225
226  subseg_change (seg, (int) subseg);
227
228  if (seg == absolute_section)
229    {
230      frchain_now = &absolute_frchain;
231      frag_now = &zero_address_frag;
232      return;
233    }
234
235  assert (frchain_now == 0
236	  || now_seg == undefined_section
237	  || frchain_now->frch_last == frag_now);
238
239  /*
240   * Attempt to find or make a frchain for that sub seg.
241   * Crawl along chain of frchainSs, begins @ frchain_root.
242   * If we need to make a frchainS, link it into correct
243   * position of chain rooted in frchain_root.
244   */
245  for (frcP = *(lastPP = &frchain_root);
246       frcP && frcP->frch_seg <= seg;
247       frcP = *(lastPP = &frcP->frch_next))
248    {
249      if (frcP->frch_seg == seg
250	  && frcP->frch_subseg >= subseg)
251	{
252	  break;
253	}
254    }
255  /*
256   * frcP:		Address of the 1st frchainS in correct segment with
257   *		frch_subseg >= subseg.
258   *		We want to either use this frchainS, or we want
259   *		to insert a new frchainS just before it.
260   *
261   *		If frcP==NULL, then we are at the end of the chain
262   *		of frchainS-s. A NULL frcP means we fell off the end
263   *		of the chain looking for a
264   *		frch_subseg >= subseg, so we
265   *		must make a new frchainS.
266   *
267   *		If we ever maintain a pointer to
268   *		the last frchainS in the chain, we change that pointer
269   *		ONLY when frcP==NULL.
270   *
271   * lastPP:	Address of the pointer with value frcP;
272   *		Never NULL.
273   *		May point to frchain_root.
274   *
275   */
276  if (!frcP
277      || (frcP->frch_seg > seg
278	  || frcP->frch_subseg > subseg))	/* Kinky logic only works with 2 segments. */
279    {
280      /*
281       * This should be the only code that creates a frchainS.
282       */
283      extern fragS *frag_alloc ();
284      newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
285      newP->frch_subseg = subseg;
286      newP->frch_seg = seg;
287#ifdef BFD_ASSEMBLER
288      newP->fix_root = NULL;
289      newP->fix_tail = NULL;
290#endif
291      obstack_begin (&newP->frch_obstack, 5000);
292#if __GNUC__ >= 2
293      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
294#endif
295      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
296      newP->frch_frag_now->fr_type = rs_fill;
297
298      newP->frch_root = newP->frch_last = newP->frch_frag_now;
299
300      *lastPP = newP;
301      newP->frch_next = frcP;	/* perhaps NULL */
302      frcP = newP;
303    }
304  /*
305   * Here with frcP pointing to the frchainS for subseg.
306   */
307  frchain_now = frcP;
308  frag_now = frcP->frch_frag_now;
309
310  assert (frchain_now->frch_last == frag_now);
311}
312
313/*
314 *			subseg_set(segT, subsegT)
315 *
316 * If you attempt to change to the current subsegment, nothing happens.
317 *
318 * In:	segT, subsegT code for new subsegment.
319 *	frag_now -> incomplete frag for current subsegment.
320 *	If frag_now==NULL, then there is no old, incomplete frag, so
321 *	the old frag is not closed off.
322 *
323 * Out:	now_subseg, now_seg updated.
324 *	Frchain_now points to the (possibly new) struct frchain for this
325 *	sub-segment.
326 *	Frchain_root updated if needed.
327 */
328
329#ifndef BFD_ASSEMBLER
330
331segT
332subseg_new (segname, subseg)
333     const char *segname;
334     subsegT subseg;
335{
336  int i;
337
338  for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
339    {
340      const char *s;
341
342      s = segment_name ((segT) i);
343      if (strcmp (segname, s) == 0
344	  || (segname[0] == '.'
345	      && strcmp (segname + 1, s) == 0))
346	{
347	  subseg_set ((segT) i, subseg);
348	  return (segT) i;
349	}
350#ifdef obj_segment_name
351      s = obj_segment_name ((segT) i);
352      if (strcmp (segname, s) == 0
353	  || (segname[0] == '.'
354	      && strcmp (segname + 1, s) == 0))
355	{
356	  subseg_set ((segT) i, subseg);
357	  return (segT) i;
358	}
359#endif
360    }
361
362#ifdef obj_add_segment
363  {
364    segT new_seg;
365    new_seg = obj_add_segment (segname);
366    subseg_set (new_seg, subseg);
367    return new_seg;
368  }
369#else
370  as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname);
371  return now_seg;
372#endif
373}
374
375void
376subseg_set (seg, subseg)	/* begin assembly for a new sub-segment */
377     register segT seg;		/* SEG_DATA or SEG_TEXT */
378     register subsegT subseg;
379{
380#ifndef MANY_SEGMENTS
381  know (seg == SEG_DATA
382	|| seg == SEG_TEXT
383	|| seg == SEG_BSS
384	|| seg == SEG_ABSOLUTE);
385#endif
386
387  if (seg != now_seg || subseg != now_subseg)
388    {				/* we just changed sub-segments */
389      subseg_set_rest (seg, subseg);
390    }
391  mri_common_symbol = NULL;
392}
393
394#else /* BFD_ASSEMBLER */
395
396segT
397subseg_get (segname, force_new)
398     const char *segname;
399     int force_new;
400{
401  segT secptr;
402  segment_info_type *seginfo;
403  const char *now_seg_name = (now_seg
404			      ? bfd_get_section_name (stdoutput, now_seg)
405			      : 0);
406
407  if (!force_new
408      && now_seg_name
409      && (now_seg_name == segname
410	  || !strcmp (now_seg_name, segname)))
411    return now_seg;
412
413  if (!force_new)
414    secptr = bfd_make_section_old_way (stdoutput, segname);
415  else
416    secptr = bfd_make_section_anyway (stdoutput, segname);
417
418  seginfo = seg_info (secptr);
419  if (! seginfo)
420    {
421      /* Check whether output_section is set first because secptr may
422         be bfd_abs_section_ptr.  */
423      if (secptr->output_section != secptr)
424	secptr->output_section = secptr;
425      seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
426      memset ((PTR) seginfo, 0, sizeof (*seginfo));
427      seginfo->fix_root = NULL;
428      seginfo->fix_tail = NULL;
429      seginfo->bfd_section = secptr;
430      if (secptr == bfd_abs_section_ptr)
431	abs_seg_info = seginfo;
432      else if (secptr == bfd_und_section_ptr)
433	und_seg_info = seginfo;
434      else
435	bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
436      seginfo->frchainP = NULL;
437      seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
438      seginfo->sym = NULL;
439      seginfo->dot = NULL;
440    }
441  return secptr;
442}
443
444segT
445subseg_new (segname, subseg)
446     const char *segname;
447     subsegT subseg;
448{
449  segT secptr;
450  segment_info_type *seginfo;
451
452  secptr = subseg_get (segname, 0);
453  subseg_set_rest (secptr, subseg);
454  seginfo = seg_info (secptr);
455  if (! seginfo->frchainP)
456    seginfo->frchainP = frchain_now;
457  return secptr;
458}
459
460/* Like subseg_new, except a new section is always created, even if
461   a section with that name already exists.  */
462segT
463subseg_force_new (segname, subseg)
464     const char *segname;
465     subsegT subseg;
466{
467  segT secptr;
468  segment_info_type *seginfo;
469
470  secptr = subseg_get (segname, 1);
471  subseg_set_rest (secptr, subseg);
472  seginfo = seg_info (secptr);
473  if (! seginfo->frchainP)
474    seginfo->frchainP = frchain_now;
475  return secptr;
476}
477
478void
479subseg_set (secptr, subseg)
480     segT secptr;
481     subsegT subseg;
482{
483  if (! (secptr == now_seg && subseg == now_subseg))
484    subseg_set_rest (secptr, subseg);
485  mri_common_symbol = NULL;
486}
487
488#ifndef obj_sec_sym_ok_for_reloc
489#define obj_sec_sym_ok_for_reloc(SEC)	0
490#endif
491
492/* Get the gas information we are storing for a section.  */
493
494segment_info_type *
495seg_info (sec)
496     segT sec;
497{
498  if (sec == bfd_abs_section_ptr)
499    return abs_seg_info;
500  else if (sec == bfd_und_section_ptr)
501    return und_seg_info;
502  else
503    return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
504}
505
506symbolS *
507section_symbol (sec)
508     segT sec;
509{
510  segment_info_type *seginfo = seg_info (sec);
511  symbolS *s;
512
513  if (seginfo == 0)
514    abort ();
515  if (seginfo->sym)
516    return seginfo->sym;
517
518#ifndef EMIT_SECTION_SYMBOLS
519#define EMIT_SECTION_SYMBOLS 1
520#endif
521
522  if (! EMIT_SECTION_SYMBOLS
523#ifdef BFD_ASSEMBLER
524      || symbol_table_frozen
525#endif
526      )
527    /* Here we know it won't be going into the symbol table.  */
528    s = symbol_create (sec->name, sec, 0, &zero_address_frag);
529  else
530    s = symbol_new (sec->name, sec, 0, &zero_address_frag);
531  S_CLEAR_EXTERNAL (s);
532
533  /* Use the BFD section symbol, if possible.  */
534  if (obj_sec_sym_ok_for_reloc (sec))
535    s->bsym = sec->symbol;
536
537  seginfo->sym = s;
538  return s;
539}
540
541#endif /* BFD_ASSEMBLER */
542
543void
544subsegs_print_statistics (file)
545     FILE *file;
546{
547  frchainS *frchp;
548  fprintf (file, "frag chains:\n");
549  for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
550    {
551      int count = 0;
552      fragS *fragp;
553
554      /* If frch_subseg is non-zero, it's probably been chained onto
555	 the end of a previous subsection.  Don't count it again.  */
556      if (frchp->frch_subseg != 0)
557	continue;
558
559      /* Skip gas-internal sections.  */
560      if (segment_name (frchp->frch_seg)[0] == '*')
561	continue;
562
563      for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
564	{
565#if 0
566	  switch (fragp->fr_type)
567	    {
568	    case rs_fill:
569	      fprintf (file, "f"); break;
570	    case rs_align:
571	      fprintf (file, "a"); break;
572	    case rs_align_code:
573	      fprintf (file, "c"); break;
574	    case rs_org:
575	      fprintf (file, "o"); break;
576	    case rs_machine_dependent:
577	      fprintf (file, "m"); break;
578	    case rs_space:
579	      fprintf (file, "s"); break;
580	    case 0:
581	      fprintf (file, "0"); break;
582	    default:
583	      fprintf (file, "?"); break;
584	    }
585#endif
586	  count++;
587	}
588      fprintf (file, "\n");
589      fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
590	       segment_name (frchp->frch_seg), count);
591    }
592}
593
594/* end of subsegs.c */
595