2001-01-10 Kazu Hirata <kazu@hxi.com>
[deliverable/binutils-gdb.git] / gas / subsegs.c
CommitLineData
252b5132 1/* subsegs.c - subsegments -
f0e652b4 2 Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
252b5132
RH
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
ef99799a 22/* Segments & sub-segments. */
252b5132
RH
23
24#include "as.h"
25
26#include "subsegs.h"
27#include "obstack.h"
28
29frchainS *frchain_root, *frchain_now;
30
31static struct obstack frchains;
32
33#ifndef BFD_ASSEMBLER
34#ifdef MANY_SEGMENTS
35segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
36
37#else
f0e652b4 38/* Commented in "subsegs.h". */
252b5132
RH
39frchainS *data0_frchainP, *bss0_frchainP;
40
41#endif /* MANY_SEGMENTS */
ef99799a 42char const *const seg_name[] = {
252b5132
RH
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 "",
f0e652b4 62}; /* Used by error reporters, dumpers etc. */
252b5132
RH
63#else /* BFD_ASSEMBLER */
64
65/* Gas segment information for bfd_abs_section_ptr and
66 bfd_und_section_ptr. */
67static segment_info_type *abs_seg_info;
68static segment_info_type *und_seg_info;
69
70#endif /* BFD_ASSEMBLER */
71
72static void subseg_set_rest PARAMS ((segT, subsegT));
73
74static fragS dummy_frag;
75
76static frchainS absolute_frchain;
77\f
78void
79subsegs_begin ()
80{
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
96
97 obstack_begin (&frchains, chunksize);
98#if __GNUC__ >= 2
99 obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
100#endif
101
102 frchain_root = NULL;
f0e652b4 103 frchain_now = NULL; /* Warn new_subseg() that we are booting. */
252b5132
RH
104
105 frag_now = &dummy_frag;
106
107#ifndef BFD_ASSEMBLER
f0e652b4 108 now_subseg = 42; /* Lie for 1st call to subseg_new. */
252b5132
RH
109#ifdef MANY_SEGMENTS
110 {
111 int i;
112 for (i = SEG_E0; i < SEG_UNKNOWN; i++)
113 {
114 subseg_set (i, 0);
115 segment_info[i].frchainP = frchain_now;
116 }
117 }
118#else
119 subseg_set (SEG_DATA, 0); /* .data 0 */
120 data0_frchainP = frchain_now;
121
122 subseg_set (SEG_BSS, 0);
123 bss0_frchainP = frchain_now;
124
125#endif /* ! MANY_SEGMENTS */
126#endif /* ! BFD_ASSEMBLER */
127
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;
135}
136\f
137/*
138 * subseg_change()
139 *
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.
146 */
147void
148subseg_change (seg, subseg)
149 register segT seg;
150 register int subseg;
151{
152 now_seg = seg;
153 now_subseg = subseg;
154
155 if (now_seg == absolute_section)
156 return;
157
158#ifdef BFD_ASSEMBLER
159 {
160 segment_info_type *seginfo;
161 seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
162 if (! seginfo)
163 {
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);
176 }
177 }
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)
184 {
185 seg_fix_rootP = &data_fix_root;
186 seg_fix_tailP = &data_fix_tail;
187 }
188 else if (seg == SEG_TEXT)
189 {
190 seg_fix_rootP = &text_fix_root;
191 seg_fix_tailP = &text_fix_tail;
192 }
193 else
194 {
195 know (seg == SEG_BSS);
196 seg_fix_rootP = &bss_fix_root;
197 seg_fix_tailP = &bss_fix_tail;
198 }
199
200#endif
201#endif
202}
203\f
204static void
205subseg_set_rest (seg, subseg)
206 segT seg;
207 subsegT subseg;
208{
209 register frchainS *frcP; /* crawl frchain chain */
210 register frchainS **lastPP; /* address of last pointer */
211 frchainS *newP; /* address of new frchain */
212
213 mri_common_symbol = NULL;
214
215 if (frag_now && frchain_now)
216 frchain_now->frch_frag_now = frag_now;
217
218 assert (frchain_now == 0
219 || now_seg == undefined_section
220 || now_seg == absolute_section
221 || frchain_now->frch_last == frag_now);
222
223 subseg_change (seg, (int) subseg);
224
225 if (seg == absolute_section)
226 {
227 frchain_now = &absolute_frchain;
228 frag_now = &zero_address_frag;
229 return;
230 }
231
232 assert (frchain_now == 0
233 || now_seg == undefined_section
234 || frchain_now->frch_last == frag_now);
235
236 /*
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.
241 */
242 for (frcP = *(lastPP = &frchain_root);
243 frcP && frcP->frch_seg <= seg;
244 frcP = *(lastPP = &frcP->frch_next))
245 {
246 if (frcP->frch_seg == seg
247 && frcP->frch_subseg >= subseg)
248 {
249 break;
250 }
251 }
252 /*
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.
257 *
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.
263 *
264 * If we ever maintain a pointer to
265 * the last frchainS in the chain, we change that pointer
266 * ONLY when frcP==NULL.
267 *
268 * lastPP: Address of the pointer with value frcP;
269 * Never NULL.
270 * May point to frchain_root.
271 *
272 */
273 if (!frcP
274 || (frcP->frch_seg > seg
f0e652b4 275 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
252b5132
RH
276 {
277 /*
278 * This should be the only code that creates a frchainS.
279 */
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;
293
294 newP->frch_root = newP->frch_last = newP->frch_frag_now;
295
296 *lastPP = newP;
297 newP->frch_next = frcP; /* perhaps NULL */
298
299#ifdef BFD_ASSEMBLER
300 {
301 segment_info_type *seginfo;
302 seginfo = seg_info (seg);
303 if (seginfo && seginfo->frchainP == frcP)
304 seginfo->frchainP = newP;
305 }
306#endif
f0e652b4 307
252b5132
RH
308 frcP = newP;
309 }
310 /*
311 * Here with frcP pointing to the frchainS for subseg.
312 */
313 frchain_now = frcP;
314 frag_now = frcP->frch_frag_now;
315
316 assert (frchain_now->frch_last == frag_now);
317}
318
319/*
320 * subseg_set(segT, subsegT)
321 *
322 * If you attempt to change to the current subsegment, nothing happens.
323 *
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.
328 *
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.
333 */
334
335#ifndef BFD_ASSEMBLER
336
337segT
338subseg_new (segname, subseg)
339 const char *segname;
340 subsegT subseg;
341{
342 int i;
343
344 for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
345 {
346 const char *s;
347
348 s = segment_name ((segT) i);
349 if (strcmp (segname, s) == 0
350 || (segname[0] == '.'
351 && strcmp (segname + 1, s) == 0))
352 {
353 subseg_set ((segT) i, subseg);
354 return (segT) i;
355 }
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))
361 {
362 subseg_set ((segT) i, subseg);
363 return (segT) i;
364 }
365#endif
366 }
367
368#ifdef obj_add_segment
369 {
370 segT new_seg;
371 new_seg = obj_add_segment (segname);
372 subseg_set (new_seg, subseg);
373 return new_seg;
374 }
375#else
376 as_bad (_("Attempt to switch to nonexistent segment \"%s\""), segname);
377 return now_seg;
378#endif
379}
380
381void
382subseg_set (seg, subseg) /* begin assembly for a new sub-segment */
383 register segT seg; /* SEG_DATA or SEG_TEXT */
384 register subsegT subseg;
385{
386#ifndef MANY_SEGMENTS
387 know (seg == SEG_DATA
388 || seg == SEG_TEXT
389 || seg == SEG_BSS
390 || seg == SEG_ABSOLUTE);
391#endif
392
393 if (seg != now_seg || subseg != now_subseg)
394 { /* we just changed sub-segments */
395 subseg_set_rest (seg, subseg);
396 }
397 mri_common_symbol = NULL;
398}
399
400#else /* BFD_ASSEMBLER */
401
402segT
403subseg_get (segname, force_new)
404 const char *segname;
405 int force_new;
406{
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);
412
413 if (!force_new
414 && now_seg_name
415 && (now_seg_name == segname
416 || !strcmp (now_seg_name, segname)))
417 return now_seg;
418
419 if (!force_new)
420 secptr = bfd_make_section_old_way (stdoutput, segname);
421 else
422 secptr = bfd_make_section_anyway (stdoutput, segname);
423
424 seginfo = seg_info (secptr);
425 if (! seginfo)
426 {
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;
446 }
447 return secptr;
448}
449
450segT
451subseg_new (segname, subseg)
452 const char *segname;
453 subsegT subseg;
454{
455 segT secptr;
456 segment_info_type *seginfo;
457
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;
464}
465
466/* Like subseg_new, except a new section is always created, even if
467 a section with that name already exists. */
468segT
469subseg_force_new (segname, subseg)
470 const char *segname;
471 subsegT subseg;
472{
473 segT secptr;
474 segment_info_type *seginfo;
475
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;
482}
483
484void
485subseg_set (secptr, subseg)
486 segT secptr;
487 subsegT subseg;
488{
489 if (! (secptr == now_seg && subseg == now_subseg))
490 subseg_set_rest (secptr, subseg);
491 mri_common_symbol = NULL;
492}
493
494#ifndef obj_sec_sym_ok_for_reloc
495#define obj_sec_sym_ok_for_reloc(SEC) 0
496#endif
497
498/* Get the gas information we are storing for a section. */
499
500segment_info_type *
501seg_info (sec)
502 segT sec;
503{
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);
510}
511
512symbolS *
513section_symbol (sec)
514 segT sec;
515{
516 segment_info_type *seginfo = seg_info (sec);
517 symbolS *s;
518
519 if (seginfo == 0)
520 abort ();
521 if (seginfo->sym)
522 return seginfo->sym;
523
524#ifndef EMIT_SECTION_SYMBOLS
525#define EMIT_SECTION_SYMBOLS 1
526#endif
527
528 if (! EMIT_SECTION_SYMBOLS
529#ifdef BFD_ASSEMBLER
530 || symbol_table_frozen
531#endif
532 )
533 {
534 /* Here we know it won't be going into the symbol table. */
535 s = symbol_create (sec->name, sec, 0, &zero_address_frag);
536 }
537 else
538 {
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
543 {
544 if (S_GET_SEGMENT (s) == undefined_section)
545 {
546 S_SET_SEGMENT (s, sec);
49309057 547 symbol_set_frag (s, &zero_address_frag);
252b5132
RH
548 }
549 }
550 }
551
552 S_CLEAR_EXTERNAL (s);
553
554 /* Use the BFD section symbol, if possible. */
555 if (obj_sec_sym_ok_for_reloc (sec))
49309057 556 symbol_set_bfdsym (s, sec->symbol);
252b5132
RH
557
558 seginfo->sym = s;
559 return s;
560}
561
562#endif /* BFD_ASSEMBLER */
563
b9e57a38
ILT
564/* Return whether the specified segment is thought to hold text. */
565
be2acf27 566#ifndef BFD_ASSEMBLER
ef99799a 567const char * const nontext_section_names[] = {
be2acf27
ILT
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
577};
578#endif /* ! BFD_ASSEMBLER */
579
b9e57a38
ILT
580int
581subseg_text_p (sec)
582 segT sec;
583{
584#ifdef BFD_ASSEMBLER
585 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
be2acf27
ILT
586#else /* ! BFD_ASSEMBLER */
587 const char * const *p;
588
589 if (sec == data_section || sec == bss_section)
264d6861 590 return 0;
be2acf27
ILT
591
592 for (p = nontext_section_names; *p != NULL; ++p)
593 {
594 if (strcmp (segment_name (sec), *p) == 0)
264d6861 595 return 0;
be2acf27
ILT
596
597#ifdef obj_segment_name
598 if (strcmp (obj_segment_name (sec), *p) == 0)
264d6861 599 return 0;
b9e57a38 600#endif
be2acf27
ILT
601 }
602
264d6861 603 return 1;
be2acf27
ILT
604
605#endif /* ! BFD_ASSEMBLER */
b9e57a38
ILT
606}
607
252b5132
RH
608void
609subsegs_print_statistics (file)
610 FILE *file;
611{
612 frchainS *frchp;
613 fprintf (file, "frag chains:\n");
614 for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
615 {
616 int count = 0;
617 fragS *fragp;
618
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;
623
624 /* Skip gas-internal sections. */
625 if (segment_name (frchp->frch_seg)[0] == '*')
626 continue;
627
628 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
629 {
630#if 0
631 switch (fragp->fr_type)
632 {
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;
649 }
650#endif
651 count++;
652 }
653 fprintf (file, "\n");
654 fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
655 segment_name (frchp->frch_seg), count);
656 }
657}
658
659/* end of subsegs.c */
This page took 0.136105 seconds and 4 git commands to generate.