merge from gcc
[binutils.git] / gas / subsegs.c
blob8b0679cbc4c478d678ae677e134c84a9ccb586a6
1 /* subsegs.c - subsegments -
2 Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3 1999, 2000, 2002, 2004
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 (segT, subsegT);
75 static fragS dummy_frag;
77 static frchainS absolute_frchain;
79 void
80 subsegs_begin (void)
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 (register segT seg, register int subseg)
151 now_seg = seg;
152 now_subseg = subseg;
154 if (now_seg == absolute_section)
155 return;
157 #ifdef BFD_ASSEMBLER
159 segment_info_type *seginfo;
160 seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
161 if (! seginfo)
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);
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)
184 seg_fix_rootP = &data_fix_root;
185 seg_fix_tailP = &data_fix_tail;
187 else if (seg == SEG_TEXT)
189 seg_fix_rootP = &text_fix_root;
190 seg_fix_tailP = &text_fix_tail;
192 else
194 know (seg == SEG_BSS);
195 seg_fix_rootP = &bss_fix_root;
196 seg_fix_tailP = &bss_fix_tail;
199 #endif
200 #endif
203 static void
204 subseg_set_rest (segT seg, subsegT subseg)
206 register frchainS *frcP; /* crawl frchain chain */
207 register frchainS **lastPP; /* address of last pointer */
208 frchainS *newP; /* address of new frchain */
210 mri_common_symbol = NULL;
212 if (frag_now && frchain_now)
213 frchain_now->frch_frag_now = frag_now;
215 assert (frchain_now == 0
216 || now_seg == undefined_section
217 || now_seg == absolute_section
218 || frchain_now->frch_last == frag_now);
220 subseg_change (seg, (int) subseg);
222 if (seg == absolute_section)
224 frchain_now = &absolute_frchain;
225 frag_now = &zero_address_frag;
226 return;
229 assert (frchain_now == 0
230 || now_seg == undefined_section
231 || frchain_now->frch_last == frag_now);
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.
239 for (frcP = *(lastPP = &frchain_root);
240 frcP && frcP->frch_seg <= seg;
241 frcP = *(lastPP = &frcP->frch_next))
243 if (frcP->frch_seg == seg
244 && frcP->frch_subseg >= subseg)
246 break;
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.
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.
261 * If we ever maintain a pointer to
262 * the last frchainS in the chain, we change that pointer
263 * ONLY when frcP==NULL.
265 * lastPP: Address of the pointer with value frcP;
266 * Never NULL.
267 * May point to frchain_root.
270 if (!frcP
271 || (frcP->frch_seg > seg
272 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
275 * This should be the only code that creates a frchainS.
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;
291 newP->frch_root = newP->frch_last = newP->frch_frag_now;
293 *lastPP = newP;
294 newP->frch_next = frcP; /* perhaps NULL */
296 #ifdef BFD_ASSEMBLER
298 segment_info_type *seginfo;
299 seginfo = seg_info (seg);
300 if (seginfo && seginfo->frchainP == frcP)
301 seginfo->frchainP = newP;
303 #endif
305 frcP = newP;
308 * Here with frcP pointing to the frchainS for subseg.
310 frchain_now = frcP;
311 frag_now = frcP->frch_frag_now;
313 assert (frchain_now->frch_last == frag_now);
317 * subseg_set(segT, subsegT)
319 * If you attempt to change to the current subsegment, nothing happens.
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.
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.
332 #ifndef BFD_ASSEMBLER
334 segT
335 subseg_new (segname, subseg)
336 const char *segname;
337 subsegT subseg;
339 int i;
341 for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
343 const char *s;
345 s = segment_name ((segT) i);
346 if (strcmp (segname, s) == 0
347 || (segname[0] == '.'
348 && strcmp (segname + 1, s) == 0))
350 subseg_set ((segT) i, subseg);
351 return (segT) i;
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))
359 subseg_set ((segT) i, subseg);
360 return (segT) i;
362 #endif
365 #ifdef obj_add_segment
367 segT new_seg;
368 new_seg = obj_add_segment (segname);
369 subseg_set (new_seg, subseg);
370 return new_seg;
372 #else
373 as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname);
374 return now_seg;
375 #endif
378 void
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;
383 #ifndef MANY_SEGMENTS
384 know (seg == SEG_DATA
385 || seg == SEG_TEXT
386 || seg == SEG_BSS
387 || seg == SEG_ABSOLUTE);
388 #endif
390 if (seg != now_seg || subseg != now_subseg)
391 { /* we just changed sub-segments */
392 subseg_set_rest (seg, subseg);
394 mri_common_symbol = NULL;
397 #else /* BFD_ASSEMBLER */
399 segT
400 subseg_get (const char *segname, int force_new)
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);
408 if (!force_new
409 && now_seg_name
410 && (now_seg_name == segname
411 || !strcmp (now_seg_name, segname)))
412 return now_seg;
414 if (!force_new)
415 secptr = bfd_make_section_old_way (stdoutput, segname);
416 else
417 secptr = bfd_make_section_anyway (stdoutput, segname);
419 #ifdef obj_sec_set_private_data
420 obj_sec_set_private_data (stdoutput, secptr);
421 #endif
423 seginfo = seg_info (secptr);
424 if (! seginfo)
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;
446 return secptr;
449 segT
450 subseg_new (const char *segname, subsegT subseg)
452 segT secptr;
453 segment_info_type *seginfo;
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;
463 /* Like subseg_new, except a new section is always created, even if
464 a section with that name already exists. */
465 segT
466 subseg_force_new (const char *segname, subsegT subseg)
468 segT secptr;
469 segment_info_type *seginfo;
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;
479 void
480 subseg_set (segT secptr, subsegT subseg)
482 if (! (secptr == now_seg && subseg == now_subseg))
483 subseg_set_rest (secptr, subseg);
484 mri_common_symbol = NULL;
487 #ifndef obj_sec_sym_ok_for_reloc
488 #define obj_sec_sym_ok_for_reloc(SEC) 0
489 #endif
491 /* Get the gas information we are storing for a section. */
493 segment_info_type *
494 seg_info (segT sec)
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);
504 symbolS *
505 section_symbol (segT sec)
507 segment_info_type *seginfo = seg_info (sec);
508 symbolS *s;
510 if (seginfo == 0)
511 abort ();
512 if (seginfo->sym)
513 return seginfo->sym;
515 #ifndef EMIT_SECTION_SYMBOLS
516 #define EMIT_SECTION_SYMBOLS 1
517 #endif
519 if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
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);
524 else
526 segT seg;
527 s = symbol_find_base (sec->symbol->name, 0);
528 /* We have to make sure it is the right symbol when we
529 have multiple sections with the same section name. */
530 if (s == NULL
531 || ((seg = S_GET_SEGMENT (s)) != sec
532 && seg != undefined_section))
533 s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
534 else if (seg == undefined_section)
536 S_SET_SEGMENT (s, sec);
537 symbol_set_frag (s, &zero_address_frag);
541 S_CLEAR_EXTERNAL (s);
543 /* Use the BFD section symbol, if possible. */
544 if (obj_sec_sym_ok_for_reloc (sec))
545 symbol_set_bfdsym (s, sec->symbol);
546 else
547 symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
549 seginfo->sym = s;
550 return s;
553 #endif /* BFD_ASSEMBLER */
555 /* Return whether the specified segment is thought to hold text. */
557 #ifndef BFD_ASSEMBLER
558 const char * const nontext_section_names[] = {
559 ".eh_frame",
560 ".gcc_except_table",
561 #ifdef OBJ_COFF
562 #ifndef COFF_LONG_SECTION_NAMES
563 ".eh_fram",
564 ".gcc_exc",
565 #endif
566 #endif
567 NULL
569 #endif /* ! BFD_ASSEMBLER */
572 subseg_text_p (segT sec)
574 #ifdef BFD_ASSEMBLER
575 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
576 #else /* ! BFD_ASSEMBLER */
577 const char * const *p;
579 if (sec == data_section || sec == bss_section || sec == absolute_section)
580 return 0;
582 for (p = nontext_section_names; *p != NULL; ++p)
584 if (strcmp (segment_name (sec), *p) == 0)
585 return 0;
587 #ifdef obj_segment_name
588 if (strcmp (obj_segment_name (sec), *p) == 0)
589 return 0;
590 #endif
593 return 1;
595 #endif /* ! BFD_ASSEMBLER */
598 void
599 subsegs_print_statistics (FILE *file)
601 frchainS *frchp;
602 fprintf (file, "frag chains:\n");
603 for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
605 int count = 0;
606 fragS *fragp;
608 /* If frch_subseg is non-zero, it's probably been chained onto
609 the end of a previous subsection. Don't count it again. */
610 if (frchp->frch_subseg != 0)
611 continue;
613 /* Skip gas-internal sections. */
614 if (segment_name (frchp->frch_seg)[0] == '*')
615 continue;
617 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
619 #if 0
620 switch (fragp->fr_type)
622 case rs_fill:
623 fprintf (file, "f"); break;
624 case rs_align:
625 fprintf (file, "a"); break;
626 case rs_align_code:
627 fprintf (file, "c"); break;
628 case rs_org:
629 fprintf (file, "o"); break;
630 case rs_machine_dependent:
631 fprintf (file, "m"); break;
632 case rs_space:
633 fprintf (file, "s"); break;
634 case 0:
635 fprintf (file, "0"); break;
636 default:
637 fprintf (file, "?"); break;
639 #endif
640 count++;
642 fprintf (file, "\n");
643 fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
644 segment_name (frchp->frch_seg), count);
648 /* end of subsegs.c */