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