oops - update date on newly created entry
[binutils.git] / gas / subsegs.c
blobc8159531ef3355c11a62aff4b7b605e7f8689b35
1 /* subsegs.c - subsegments -
2 Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3 1999, 2000
4 Free Software Foundation, Inc.
6 This file is part of GAS, the GNU Assembler.
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.
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.
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. */
23 /* Segments & sub-segments. */
25 #include "as.h"
27 #include "subsegs.h"
28 #include "obstack.h"
30 frchainS *frchain_root, *frchain_now;
32 static struct obstack frchains;
34 #ifndef BFD_ASSEMBLER
35 #ifdef MANY_SEGMENTS
36 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
38 #else
39 /* Commented in "subsegs.h". */
40 frchainS *data0_frchainP, *bss0_frchainP;
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 */
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;
71 #endif /* BFD_ASSEMBLER */
73 static void subseg_set_rest PARAMS ((segT, subsegT));
75 static fragS dummy_frag;
77 static frchainS absolute_frchain;
79 void
80 subsegs_begin ()
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
98 obstack_begin (&frchains, chunksize);
99 #if __GNUC__ >= 2
100 obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
101 #endif
103 frchain_root = NULL;
104 frchain_now = NULL; /* Warn new_subseg() that we are booting. */
106 frag_now = &dummy_frag;
108 #ifndef BFD_ASSEMBLER
109 now_subseg = 42; /* Lie for 1st call to subseg_new. */
110 #ifdef MANY_SEGMENTS
112 int i;
113 for (i = SEG_E0; i < SEG_UNKNOWN; i++)
115 subseg_set (i, 0);
116 segment_info[i].frchainP = frchain_now;
119 #else
120 subseg_set (SEG_DATA, 0); /* .data 0 */
121 data0_frchainP = frchain_now;
123 subseg_set (SEG_BSS, 0);
124 bss0_frchainP = frchain_now;
126 #endif /* ! MANY_SEGMENTS */
127 #endif /* ! BFD_ASSEMBLER */
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;
139 * subseg_change()
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.
148 void
149 subseg_change (seg, subseg)
150 register segT seg;
151 register int subseg;
153 now_seg = seg;
154 now_subseg = subseg;
156 if (now_seg == absolute_section)
157 return;
159 #ifdef BFD_ASSEMBLER
161 segment_info_type *seginfo;
162 seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
163 if (! seginfo)
165 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
166 memset ((PTR) seginfo, 0, sizeof (*seginfo));
167 seginfo->fix_root = NULL;
168 seginfo->fix_tail = NULL;
169 seginfo->bfd_section = seg;
170 seginfo->sym = 0;
171 if (seg == bfd_abs_section_ptr)
172 abs_seg_info = seginfo;
173 else if (seg == bfd_und_section_ptr)
174 und_seg_info = seginfo;
175 else
176 bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
179 #else
180 #ifdef MANY_SEGMENTS
181 seg_fix_rootP = &segment_info[seg].fix_root;
182 seg_fix_tailP = &segment_info[seg].fix_tail;
183 #else
184 if (seg == SEG_DATA)
186 seg_fix_rootP = &data_fix_root;
187 seg_fix_tailP = &data_fix_tail;
189 else if (seg == SEG_TEXT)
191 seg_fix_rootP = &text_fix_root;
192 seg_fix_tailP = &text_fix_tail;
194 else
196 know (seg == SEG_BSS);
197 seg_fix_rootP = &bss_fix_root;
198 seg_fix_tailP = &bss_fix_tail;
201 #endif
202 #endif
205 static void
206 subseg_set_rest (seg, subseg)
207 segT seg;
208 subsegT subseg;
210 register frchainS *frcP; /* crawl frchain chain */
211 register frchainS **lastPP; /* address of last pointer */
212 frchainS *newP; /* address of new frchain */
214 mri_common_symbol = NULL;
216 if (frag_now && frchain_now)
217 frchain_now->frch_frag_now = frag_now;
219 assert (frchain_now == 0
220 || now_seg == undefined_section
221 || now_seg == absolute_section
222 || frchain_now->frch_last == frag_now);
224 subseg_change (seg, (int) subseg);
226 if (seg == absolute_section)
228 frchain_now = &absolute_frchain;
229 frag_now = &zero_address_frag;
230 return;
233 assert (frchain_now == 0
234 || now_seg == undefined_section
235 || frchain_now->frch_last == frag_now);
238 * Attempt to find or make a frchain for that sub seg.
239 * Crawl along chain of frchainSs, begins @ frchain_root.
240 * If we need to make a frchainS, link it into correct
241 * position of chain rooted in frchain_root.
243 for (frcP = *(lastPP = &frchain_root);
244 frcP && frcP->frch_seg <= seg;
245 frcP = *(lastPP = &frcP->frch_next))
247 if (frcP->frch_seg == seg
248 && frcP->frch_subseg >= subseg)
250 break;
254 * frcP: Address of the 1st frchainS in correct segment with
255 * frch_subseg >= subseg.
256 * We want to either use this frchainS, or we want
257 * to insert a new frchainS just before it.
259 * If frcP==NULL, then we are at the end of the chain
260 * of frchainS-s. A NULL frcP means we fell off the end
261 * of the chain looking for a
262 * frch_subseg >= subseg, so we
263 * must make a new frchainS.
265 * If we ever maintain a pointer to
266 * the last frchainS in the chain, we change that pointer
267 * ONLY when frcP==NULL.
269 * lastPP: Address of the pointer with value frcP;
270 * Never NULL.
271 * May point to frchain_root.
274 if (!frcP
275 || (frcP->frch_seg > seg
276 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
279 * This should be the only code that creates a frchainS.
281 newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
282 newP->frch_subseg = subseg;
283 newP->frch_seg = seg;
284 #ifdef BFD_ASSEMBLER
285 newP->fix_root = NULL;
286 newP->fix_tail = NULL;
287 #endif
288 obstack_begin (&newP->frch_obstack, chunksize);
289 #if __GNUC__ >= 2
290 obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
291 #endif
292 newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
293 newP->frch_frag_now->fr_type = rs_fill;
295 newP->frch_root = newP->frch_last = newP->frch_frag_now;
297 *lastPP = newP;
298 newP->frch_next = frcP; /* perhaps NULL */
300 #ifdef BFD_ASSEMBLER
302 segment_info_type *seginfo;
303 seginfo = seg_info (seg);
304 if (seginfo && seginfo->frchainP == frcP)
305 seginfo->frchainP = newP;
307 #endif
309 frcP = newP;
312 * Here with frcP pointing to the frchainS for subseg.
314 frchain_now = frcP;
315 frag_now = frcP->frch_frag_now;
317 assert (frchain_now->frch_last == frag_now);
321 * subseg_set(segT, subsegT)
323 * If you attempt to change to the current subsegment, nothing happens.
325 * In: segT, subsegT code for new subsegment.
326 * frag_now -> incomplete frag for current subsegment.
327 * If frag_now==NULL, then there is no old, incomplete frag, so
328 * the old frag is not closed off.
330 * Out: now_subseg, now_seg updated.
331 * Frchain_now points to the (possibly new) struct frchain for this
332 * sub-segment.
333 * Frchain_root updated if needed.
336 #ifndef BFD_ASSEMBLER
338 segT
339 subseg_new (segname, subseg)
340 const char *segname;
341 subsegT subseg;
343 int i;
345 for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
347 const char *s;
349 s = segment_name ((segT) i);
350 if (strcmp (segname, s) == 0
351 || (segname[0] == '.'
352 && strcmp (segname + 1, s) == 0))
354 subseg_set ((segT) i, subseg);
355 return (segT) i;
357 #ifdef obj_segment_name
358 s = obj_segment_name ((segT) i);
359 if (strcmp (segname, s) == 0
360 || (segname[0] == '.'
361 && strcmp (segname + 1, s) == 0))
363 subseg_set ((segT) i, subseg);
364 return (segT) i;
366 #endif
369 #ifdef obj_add_segment
371 segT new_seg;
372 new_seg = obj_add_segment (segname);
373 subseg_set (new_seg, subseg);
374 return new_seg;
376 #else
377 as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname);
378 return now_seg;
379 #endif
382 void
383 subseg_set (seg, subseg) /* begin assembly for a new sub-segment */
384 register segT seg; /* SEG_DATA or SEG_TEXT */
385 register subsegT subseg;
387 #ifndef MANY_SEGMENTS
388 know (seg == SEG_DATA
389 || seg == SEG_TEXT
390 || seg == SEG_BSS
391 || seg == SEG_ABSOLUTE);
392 #endif
394 if (seg != now_seg || subseg != now_subseg)
395 { /* we just changed sub-segments */
396 subseg_set_rest (seg, subseg);
398 mri_common_symbol = NULL;
401 #else /* BFD_ASSEMBLER */
403 segT
404 subseg_get (segname, force_new)
405 const char *segname;
406 int force_new;
408 segT secptr;
409 segment_info_type *seginfo;
410 const char *now_seg_name = (now_seg
411 ? bfd_get_section_name (stdoutput, now_seg)
412 : 0);
414 if (!force_new
415 && now_seg_name
416 && (now_seg_name == segname
417 || !strcmp (now_seg_name, segname)))
418 return now_seg;
420 if (!force_new)
421 secptr = bfd_make_section_old_way (stdoutput, segname);
422 else
423 secptr = bfd_make_section_anyway (stdoutput, segname);
425 seginfo = seg_info (secptr);
426 if (! seginfo)
428 /* Check whether output_section is set first because secptr may
429 be bfd_abs_section_ptr. */
430 if (secptr->output_section != secptr)
431 secptr->output_section = secptr;
432 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
433 memset ((PTR) seginfo, 0, sizeof (*seginfo));
434 seginfo->fix_root = NULL;
435 seginfo->fix_tail = NULL;
436 seginfo->bfd_section = secptr;
437 if (secptr == bfd_abs_section_ptr)
438 abs_seg_info = seginfo;
439 else if (secptr == bfd_und_section_ptr)
440 und_seg_info = seginfo;
441 else
442 bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
443 seginfo->frchainP = NULL;
444 seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
445 seginfo->sym = NULL;
446 seginfo->dot = NULL;
448 return secptr;
451 segT
452 subseg_new (segname, subseg)
453 const char *segname;
454 subsegT subseg;
456 segT secptr;
457 segment_info_type *seginfo;
459 secptr = subseg_get (segname, 0);
460 subseg_set_rest (secptr, subseg);
461 seginfo = seg_info (secptr);
462 if (! seginfo->frchainP)
463 seginfo->frchainP = frchain_now;
464 return secptr;
467 /* Like subseg_new, except a new section is always created, even if
468 a section with that name already exists. */
469 segT
470 subseg_force_new (segname, subseg)
471 const char *segname;
472 subsegT subseg;
474 segT secptr;
475 segment_info_type *seginfo;
477 secptr = subseg_get (segname, 1);
478 subseg_set_rest (secptr, subseg);
479 seginfo = seg_info (secptr);
480 if (! seginfo->frchainP)
481 seginfo->frchainP = frchain_now;
482 return secptr;
485 void
486 subseg_set (secptr, subseg)
487 segT secptr;
488 subsegT subseg;
490 if (! (secptr == now_seg && subseg == now_subseg))
491 subseg_set_rest (secptr, subseg);
492 mri_common_symbol = NULL;
495 #ifndef obj_sec_sym_ok_for_reloc
496 #define obj_sec_sym_ok_for_reloc(SEC) 0
497 #endif
499 /* Get the gas information we are storing for a section. */
501 segment_info_type *
502 seg_info (sec)
503 segT sec;
505 if (sec == bfd_abs_section_ptr)
506 return abs_seg_info;
507 else if (sec == bfd_und_section_ptr)
508 return und_seg_info;
509 else
510 return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
513 symbolS *
514 section_symbol (sec)
515 segT sec;
517 segment_info_type *seginfo = seg_info (sec);
518 symbolS *s;
520 if (seginfo == 0)
521 abort ();
522 if (seginfo->sym)
523 return seginfo->sym;
525 #ifndef EMIT_SECTION_SYMBOLS
526 #define EMIT_SECTION_SYMBOLS 1
527 #endif
529 if (! EMIT_SECTION_SYMBOLS
530 #ifdef BFD_ASSEMBLER
531 || symbol_table_frozen
532 #endif
535 /* Here we know it won't be going into the symbol table. */
536 s = symbol_create (sec->name, sec, 0, &zero_address_frag);
538 else
540 s = symbol_find_base (sec->name, 0);
541 if (s == NULL)
542 s = symbol_new (sec->name, sec, 0, &zero_address_frag);
543 else
545 if (S_GET_SEGMENT (s) == undefined_section)
547 S_SET_SEGMENT (s, sec);
548 symbol_set_frag (s, &zero_address_frag);
553 S_CLEAR_EXTERNAL (s);
555 /* Use the BFD section symbol, if possible. */
556 if (obj_sec_sym_ok_for_reloc (sec))
557 symbol_set_bfdsym (s, sec->symbol);
559 seginfo->sym = s;
560 return s;
563 #endif /* BFD_ASSEMBLER */
565 /* Return whether the specified segment is thought to hold text. */
567 #ifndef BFD_ASSEMBLER
568 const char * const nontext_section_names[] = {
569 ".eh_frame",
570 ".gcc_except_table",
571 #ifdef OBJ_COFF
572 #ifndef COFF_LONG_SECTION_NAMES
573 ".eh_fram",
574 ".gcc_exc",
575 #endif
576 #endif
577 NULL
579 #endif /* ! BFD_ASSEMBLER */
582 subseg_text_p (sec)
583 segT sec;
585 #ifdef BFD_ASSEMBLER
586 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
587 #else /* ! BFD_ASSEMBLER */
588 const char * const *p;
590 if (sec == data_section || sec == bss_section || sec == absolute_section)
591 return 0;
593 for (p = nontext_section_names; *p != NULL; ++p)
595 if (strcmp (segment_name (sec), *p) == 0)
596 return 0;
598 #ifdef obj_segment_name
599 if (strcmp (obj_segment_name (sec), *p) == 0)
600 return 0;
601 #endif
604 return 1;
606 #endif /* ! BFD_ASSEMBLER */
609 void
610 subsegs_print_statistics (file)
611 FILE *file;
613 frchainS *frchp;
614 fprintf (file, "frag chains:\n");
615 for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
617 int count = 0;
618 fragS *fragp;
620 /* If frch_subseg is non-zero, it's probably been chained onto
621 the end of a previous subsection. Don't count it again. */
622 if (frchp->frch_subseg != 0)
623 continue;
625 /* Skip gas-internal sections. */
626 if (segment_name (frchp->frch_seg)[0] == '*')
627 continue;
629 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
631 #if 0
632 switch (fragp->fr_type)
634 case rs_fill:
635 fprintf (file, "f"); break;
636 case rs_align:
637 fprintf (file, "a"); break;
638 case rs_align_code:
639 fprintf (file, "c"); break;
640 case rs_org:
641 fprintf (file, "o"); break;
642 case rs_machine_dependent:
643 fprintf (file, "m"); break;
644 case rs_space:
645 fprintf (file, "s"); break;
646 case 0:
647 fprintf (file, "0"); break;
648 default:
649 fprintf (file, "?"); break;
651 #endif
652 count++;
654 fprintf (file, "\n");
655 fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
656 segment_name (frchp->frch_seg), count);
660 /* end of subsegs.c */