subsegs.c revision 60484
1/* subsegs.c - subsegments -
2   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999
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      newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
284      newP->frch_subseg = subseg;
285      newP->frch_seg = seg;
286#ifdef BFD_ASSEMBLER
287      newP->fix_root = NULL;
288      newP->fix_tail = NULL;
289#endif
290      obstack_begin (&newP->frch_obstack, chunksize);
291#if __GNUC__ >= 2
292      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
293#endif
294      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
295      newP->frch_frag_now->fr_type = rs_fill;
296
297      newP->frch_root = newP->frch_last = newP->frch_frag_now;
298
299      *lastPP = newP;
300      newP->frch_next = frcP;	/* perhaps NULL */
301
302#ifdef BFD_ASSEMBLER
303      {
304	segment_info_type *seginfo;
305	seginfo = seg_info (seg);
306	if (seginfo && seginfo->frchainP == frcP)
307	  seginfo->frchainP = newP;
308      }
309#endif
310
311      frcP = newP;
312    }
313  /*
314   * Here with frcP pointing to the frchainS for subseg.
315   */
316  frchain_now = frcP;
317  frag_now = frcP->frch_frag_now;
318
319  assert (frchain_now->frch_last == frag_now);
320}
321
322/*
323 *			subseg_set(segT, subsegT)
324 *
325 * If you attempt to change to the current subsegment, nothing happens.
326 *
327 * In:	segT, subsegT code for new subsegment.
328 *	frag_now -> incomplete frag for current subsegment.
329 *	If frag_now==NULL, then there is no old, incomplete frag, so
330 *	the old frag is not closed off.
331 *
332 * Out:	now_subseg, now_seg updated.
333 *	Frchain_now points to the (possibly new) struct frchain for this
334 *	sub-segment.
335 *	Frchain_root updated if needed.
336 */
337
338#ifndef BFD_ASSEMBLER
339
340segT
341subseg_new (segname, subseg)
342     const char *segname;
343     subsegT subseg;
344{
345  int i;
346
347  for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
348    {
349      const char *s;
350
351      s = 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#ifdef obj_segment_name
360      s = obj_segment_name ((segT) i);
361      if (strcmp (segname, s) == 0
362	  || (segname[0] == '.'
363	      && strcmp (segname + 1, s) == 0))
364	{
365	  subseg_set ((segT) i, subseg);
366	  return (segT) i;
367	}
368#endif
369    }
370
371#ifdef obj_add_segment
372  {
373    segT new_seg;
374    new_seg = obj_add_segment (segname);
375    subseg_set (new_seg, subseg);
376    return new_seg;
377  }
378#else
379  as_bad (_("Attempt to switch to nonexistent segment \"%s\""), segname);
380  return now_seg;
381#endif
382}
383
384void
385subseg_set (seg, subseg)	/* begin assembly for a new sub-segment */
386     register segT seg;		/* SEG_DATA or SEG_TEXT */
387     register subsegT subseg;
388{
389#ifndef MANY_SEGMENTS
390  know (seg == SEG_DATA
391	|| seg == SEG_TEXT
392	|| seg == SEG_BSS
393	|| seg == SEG_ABSOLUTE);
394#endif
395
396  if (seg != now_seg || subseg != now_subseg)
397    {				/* we just changed sub-segments */
398      subseg_set_rest (seg, subseg);
399    }
400  mri_common_symbol = NULL;
401}
402
403#else /* BFD_ASSEMBLER */
404
405segT
406subseg_get (segname, force_new)
407     const char *segname;
408     int force_new;
409{
410  segT secptr;
411  segment_info_type *seginfo;
412  const char *now_seg_name = (now_seg
413			      ? bfd_get_section_name (stdoutput, now_seg)
414			      : 0);
415
416  if (!force_new
417      && now_seg_name
418      && (now_seg_name == segname
419	  || !strcmp (now_seg_name, segname)))
420    return now_seg;
421
422  if (!force_new)
423    secptr = bfd_make_section_old_way (stdoutput, segname);
424  else
425    secptr = bfd_make_section_anyway (stdoutput, segname);
426
427  seginfo = seg_info (secptr);
428  if (! seginfo)
429    {
430      /* Check whether output_section is set first because secptr may
431         be bfd_abs_section_ptr.  */
432      if (secptr->output_section != secptr)
433	secptr->output_section = secptr;
434      seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
435      memset ((PTR) seginfo, 0, sizeof (*seginfo));
436      seginfo->fix_root = NULL;
437      seginfo->fix_tail = NULL;
438      seginfo->bfd_section = secptr;
439      if (secptr == bfd_abs_section_ptr)
440	abs_seg_info = seginfo;
441      else if (secptr == bfd_und_section_ptr)
442	und_seg_info = seginfo;
443      else
444	bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
445      seginfo->frchainP = NULL;
446      seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
447      seginfo->sym = NULL;
448      seginfo->dot = NULL;
449    }
450  return secptr;
451}
452
453segT
454subseg_new (segname, subseg)
455     const char *segname;
456     subsegT subseg;
457{
458  segT secptr;
459  segment_info_type *seginfo;
460
461  secptr = subseg_get (segname, 0);
462  subseg_set_rest (secptr, subseg);
463  seginfo = seg_info (secptr);
464  if (! seginfo->frchainP)
465    seginfo->frchainP = frchain_now;
466  return secptr;
467}
468
469/* Like subseg_new, except a new section is always created, even if
470   a section with that name already exists.  */
471segT
472subseg_force_new (segname, subseg)
473     const char *segname;
474     subsegT subseg;
475{
476  segT secptr;
477  segment_info_type *seginfo;
478
479  secptr = subseg_get (segname, 1);
480  subseg_set_rest (secptr, subseg);
481  seginfo = seg_info (secptr);
482  if (! seginfo->frchainP)
483    seginfo->frchainP = frchain_now;
484  return secptr;
485}
486
487void
488subseg_set (secptr, subseg)
489     segT secptr;
490     subsegT subseg;
491{
492  if (! (secptr == now_seg && subseg == now_subseg))
493    subseg_set_rest (secptr, subseg);
494  mri_common_symbol = NULL;
495}
496
497#ifndef obj_sec_sym_ok_for_reloc
498#define obj_sec_sym_ok_for_reloc(SEC)	0
499#endif
500
501/* Get the gas information we are storing for a section.  */
502
503segment_info_type *
504seg_info (sec)
505     segT sec;
506{
507  if (sec == bfd_abs_section_ptr)
508    return abs_seg_info;
509  else if (sec == bfd_und_section_ptr)
510    return und_seg_info;
511  else
512    return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
513}
514
515symbolS *
516section_symbol (sec)
517     segT sec;
518{
519  segment_info_type *seginfo = seg_info (sec);
520  symbolS *s;
521
522  if (seginfo == 0)
523    abort ();
524  if (seginfo->sym)
525    return seginfo->sym;
526
527#ifndef EMIT_SECTION_SYMBOLS
528#define EMIT_SECTION_SYMBOLS 1
529#endif
530
531  if (! EMIT_SECTION_SYMBOLS
532#ifdef BFD_ASSEMBLER
533      || symbol_table_frozen
534#endif
535      )
536    {
537      /* Here we know it won't be going into the symbol table.  */
538      s = symbol_create (sec->name, sec, 0, &zero_address_frag);
539    }
540  else
541    {
542      s = symbol_find_base (sec->name, 0);
543      if (s == NULL)
544	s = symbol_new (sec->name, sec, 0, &zero_address_frag);
545      else
546	{
547	  if (S_GET_SEGMENT (s) == undefined_section)
548	    {
549	      S_SET_SEGMENT (s, sec);
550	      symbol_set_frag (s, &zero_address_frag);
551	    }
552	}
553    }
554
555  S_CLEAR_EXTERNAL (s);
556
557  /* Use the BFD section symbol, if possible.  */
558  if (obj_sec_sym_ok_for_reloc (sec))
559    symbol_set_bfdsym (s, sec->symbol);
560
561  seginfo->sym = s;
562  return s;
563}
564
565#endif /* BFD_ASSEMBLER */
566
567/* Return whether the specified segment is thought to hold text.  */
568
569#ifndef BFD_ASSEMBLER
570const char * const nontext_section_names[] =
571{
572  ".eh_frame",
573  ".gcc_except_table",
574#ifdef OBJ_COFF
575#ifndef COFF_LONG_SECTION_NAMES
576  ".eh_fram",
577  ".gcc_exc",
578#endif
579#endif
580  NULL
581};
582#endif /* ! BFD_ASSEMBLER */
583
584int
585subseg_text_p (sec)
586     segT sec;
587{
588#ifdef BFD_ASSEMBLER
589  return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
590#else /* ! BFD_ASSEMBLER */
591  const char * const *p;
592
593  if (sec == data_section || sec == bss_section)
594    return 0;
595
596  for (p = nontext_section_names; *p != NULL; ++p)
597    {
598      if (strcmp (segment_name (sec), *p) == 0)
599	return 0;
600
601#ifdef obj_segment_name
602      if (strcmp (obj_segment_name (sec), *p) == 0)
603	return 0;
604#endif
605    }
606
607  return 1;
608
609#endif /* ! BFD_ASSEMBLER */
610}
611
612void
613subsegs_print_statistics (file)
614     FILE *file;
615{
616  frchainS *frchp;
617  fprintf (file, "frag chains:\n");
618  for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
619    {
620      int count = 0;
621      fragS *fragp;
622
623      /* If frch_subseg is non-zero, it's probably been chained onto
624	 the end of a previous subsection.  Don't count it again.  */
625      if (frchp->frch_subseg != 0)
626	continue;
627
628      /* Skip gas-internal sections.  */
629      if (segment_name (frchp->frch_seg)[0] == '*')
630	continue;
631
632      for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
633	{
634#if 0
635	  switch (fragp->fr_type)
636	    {
637	    case rs_fill:
638	      fprintf (file, "f"); break;
639	    case rs_align:
640	      fprintf (file, "a"); break;
641	    case rs_align_code:
642	      fprintf (file, "c"); break;
643	    case rs_org:
644	      fprintf (file, "o"); break;
645	    case rs_machine_dependent:
646	      fprintf (file, "m"); break;
647	    case rs_space:
648	      fprintf (file, "s"); break;
649	    case 0:
650	      fprintf (file, "0"); break;
651	    default:
652	      fprintf (file, "?"); break;
653	    }
654#endif
655	  count++;
656	}
657      fprintf (file, "\n");
658      fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
659	       segment_name (frchp->frch_seg), count);
660    }
661}
662
663/* end of subsegs.c */
664