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