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