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