source: trunk/src/binutils/gas/subsegs.c@ 1569

Last change on this file since 1569 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 15.8 KB
Line 
1/* subsegs.c - subsegments -
2 Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3 1999, 2000, 2002
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
23/* Segments & sub-segments. */
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
39/* Commented in "subsegs.h". */
40frchainS *data0_frchainP, *bss0_frchainP;
41
42#endif /* MANY_SEGMENTS */
43char 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 */
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
79
80void
81subsegs_begin ()
82{
83 /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
84#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
85 know (SEG_ABSOLUTE == 0);
86 know (SEG_TEXT == 1);
87 know (SEG_DATA == 2);
88 know (SEG_BSS == 3);
89 know (SEG_UNKNOWN == 4);
90 know (SEG_GOOF == 5);
91 know (SEG_EXPR == 6);
92 know (SEG_DEBUG == 7);
93 know (SEG_NTV == 8);
94 know (SEG_PTV == 9);
95 know (SEG_REGISTER == 10);
96 know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
97#endif
98
99 obstack_begin (&frchains, chunksize);
100#if __GNUC__ >= 2
101 obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
102#endif
103
104 frchain_root = NULL;
105 frchain_now = NULL; /* Warn new_subseg() that we are booting. */
106
107 frag_now = &dummy_frag;
108
109#ifndef BFD_ASSEMBLER
110 now_subseg = 42; /* Lie for 1st call to subseg_new. */
111#ifdef MANY_SEGMENTS
112 {
113 int i;
114 for (i = SEG_E0; i < SEG_UNKNOWN; i++)
115 {
116 subseg_set (i, 0);
117 segment_info[i].frchainP = frchain_now;
118 }
119 }
120#else
121 subseg_set (SEG_DATA, 0); /* .data 0 */
122 data0_frchainP = frchain_now;
123
124 subseg_set (SEG_BSS, 0);
125 bss0_frchainP = frchain_now;
126
127#endif /* ! MANY_SEGMENTS */
128#endif /* ! BFD_ASSEMBLER */
129
130 absolute_frchain.frch_seg = absolute_section;
131 absolute_frchain.frch_subseg = 0;
132#ifdef BFD_ASSEMBLER
133 absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
134#endif
135 absolute_frchain.frch_frag_now = &zero_address_frag;
136 absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
137}
138
139
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
207
208static void
209subseg_set_rest (seg, subseg)
210 segT seg;
211 subsegT subseg;
212{
213 register frchainS *frcP; /* crawl frchain chain */
214 register frchainS **lastPP; /* address of last pointer */
215 frchainS *newP; /* address of new frchain */
216
217 mri_common_symbol = NULL;
218
219 if (frag_now && frchain_now)
220 frchain_now->frch_frag_now = frag_now;
221
222 assert (frchain_now == 0
223 || now_seg == undefined_section
224 || now_seg == absolute_section
225 || frchain_now->frch_last == frag_now);
226
227 subseg_change (seg, (int) subseg);
228
229 if (seg == absolute_section)
230 {
231 frchain_now = &absolute_frchain;
232 frag_now = &zero_address_frag;
233 return;
234 }
235
236 assert (frchain_now == 0
237 || now_seg == undefined_section
238 || frchain_now->frch_last == frag_now);
239
240 /*
241 * Attempt to find or make a frchain for that sub seg.
242 * Crawl along chain of frchainSs, begins @ frchain_root.
243 * If we need to make a frchainS, link it into correct
244 * position of chain rooted in frchain_root.
245 */
246 for (frcP = *(lastPP = &frchain_root);
247 frcP && frcP->frch_seg <= seg;
248 frcP = *(lastPP = &frcP->frch_next))
249 {
250 if (frcP->frch_seg == seg
251 && frcP->frch_subseg >= subseg)
252 {
253 break;
254 }
255 }
256 /*
257 * frcP: Address of the 1st frchainS in correct segment with
258 * frch_subseg >= subseg.
259 * We want to either use this frchainS, or we want
260 * to insert a new frchainS just before it.
261 *
262 * If frcP==NULL, then we are at the end of the chain
263 * of frchainS-s. A NULL frcP means we fell off the end
264 * of the chain looking for a
265 * frch_subseg >= subseg, so we
266 * must make a new frchainS.
267 *
268 * If we ever maintain a pointer to
269 * the last frchainS in the chain, we change that pointer
270 * ONLY when frcP==NULL.
271 *
272 * lastPP: Address of the pointer with value frcP;
273 * Never NULL.
274 * May point to frchain_root.
275 *
276 */
277 if (!frcP
278 || (frcP->frch_seg > seg
279 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
280 {
281 /*
282 * This should be the only code that creates a frchainS.
283 */
284 newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
285 newP->frch_subseg = subseg;
286 newP->frch_seg = seg;
287#ifdef BFD_ASSEMBLER
288 newP->fix_root = NULL;
289 newP->fix_tail = NULL;
290#endif
291 obstack_begin (&newP->frch_obstack, chunksize);
292#if __GNUC__ >= 2
293 obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
294#endif
295 newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
296 newP->frch_frag_now->fr_type = rs_fill;
297
298 newP->frch_root = newP->frch_last = newP->frch_frag_now;
299
300 *lastPP = newP;
301 newP->frch_next = frcP; /* perhaps NULL */
302
303#ifdef BFD_ASSEMBLER
304 {
305 segment_info_type *seginfo;
306 seginfo = seg_info (seg);
307 if (seginfo && seginfo->frchainP == frcP)
308 seginfo->frchainP = newP;
309 }
310#endif
311
312 frcP = newP;
313 }
314 /*
315 * Here with frcP pointing to the frchainS for subseg.
316 */
317 frchain_now = frcP;
318 frag_now = frcP->frch_frag_now;
319
320 assert (frchain_now->frch_last == frag_now);
321}
322
323/*
324 * subseg_set(segT, subsegT)
325 *
326 * If you attempt to change to the current subsegment, nothing happens.
327 *
328 * In: segT, subsegT code for new subsegment.
329 * frag_now -> incomplete frag for current subsegment.
330 * If frag_now==NULL, then there is no old, incomplete frag, so
331 * the old frag is not closed off.
332 *
333 * Out: now_subseg, now_seg updated.
334 * Frchain_now points to the (possibly new) struct frchain for this
335 * sub-segment.
336 * Frchain_root updated if needed.
337 */
338
339#ifndef BFD_ASSEMBLER
340
341segT
342subseg_new (segname, subseg)
343 const char *segname;
344 subsegT subseg;
345{
346 int i;
347
348 for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
349 {
350 const char *s;
351
352 s = segment_name ((segT) i);
353 if (strcmp (segname, s) == 0
354 || (segname[0] == '.'
355 && strcmp (segname + 1, s) == 0))
356 {
357 subseg_set ((segT) i, subseg);
358 return (segT) i;
359 }
360#ifdef obj_segment_name
361 s = obj_segment_name ((segT) i);
362 if (strcmp (segname, s) == 0
363 || (segname[0] == '.'
364 && strcmp (segname + 1, s) == 0))
365 {
366 subseg_set ((segT) i, subseg);
367 return (segT) i;
368 }
369#endif
370 }
371
372#ifdef obj_add_segment
373 {
374 segT new_seg;
375 new_seg = obj_add_segment (segname);
376 subseg_set (new_seg, subseg);
377 return new_seg;
378 }
379#else
380 as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname);
381 return now_seg;
382#endif
383}
384
385void
386subseg_set (seg, subseg) /* begin assembly for a new sub-segment */
387 register segT seg; /* SEG_DATA or SEG_TEXT */
388 register subsegT subseg;
389{
390#ifndef MANY_SEGMENTS
391 know (seg == SEG_DATA
392 || seg == SEG_TEXT
393 || seg == SEG_BSS
394 || seg == SEG_ABSOLUTE);
395#endif
396
397 if (seg != now_seg || subseg != now_subseg)
398 { /* we just changed sub-segments */
399 subseg_set_rest (seg, subseg);
400 }
401 mri_common_symbol = NULL;
402}
403
404#else /* BFD_ASSEMBLER */
405
406segT
407subseg_get (segname, force_new)
408 const char *segname;
409 int force_new;
410{
411 segT secptr;
412 segment_info_type *seginfo;
413 const char *now_seg_name = (now_seg
414 ? bfd_get_section_name (stdoutput, now_seg)
415 : 0);
416
417 if (!force_new
418 && now_seg_name
419 && (now_seg_name == segname
420 || !strcmp (now_seg_name, segname)))
421 return now_seg;
422
423 if (!force_new)
424 secptr = bfd_make_section_old_way (stdoutput, segname);
425 else
426 secptr = bfd_make_section_anyway (stdoutput, segname);
427
428 seginfo = seg_info (secptr);
429 if (! seginfo)
430 {
431 /* Check whether output_section is set first because secptr may
432 be bfd_abs_section_ptr. */
433 if (secptr->output_section != secptr)
434 secptr->output_section = secptr;
435 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
436 memset ((PTR) seginfo, 0, sizeof (*seginfo));
437 seginfo->fix_root = NULL;
438 seginfo->fix_tail = NULL;
439 seginfo->bfd_section = secptr;
440 if (secptr == bfd_abs_section_ptr)
441 abs_seg_info = seginfo;
442 else if (secptr == bfd_und_section_ptr)
443 und_seg_info = seginfo;
444 else
445 bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
446 seginfo->frchainP = NULL;
447 seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
448 seginfo->sym = NULL;
449 seginfo->dot = NULL;
450 }
451 return secptr;
452}
453
454segT
455subseg_new (segname, subseg)
456 const char *segname;
457 subsegT subseg;
458{
459 segT secptr;
460 segment_info_type *seginfo;
461
462 secptr = subseg_get (segname, 0);
463 subseg_set_rest (secptr, subseg);
464 seginfo = seg_info (secptr);
465 if (! seginfo->frchainP)
466 seginfo->frchainP = frchain_now;
467 return secptr;
468}
469
470/* Like subseg_new, except a new section is always created, even if
471 a section with that name already exists. */
472segT
473subseg_force_new (segname, subseg)
474 const char *segname;
475 subsegT subseg;
476{
477 segT secptr;
478 segment_info_type *seginfo;
479
480 secptr = subseg_get (segname, 1);
481 subseg_set_rest (secptr, subseg);
482 seginfo = seg_info (secptr);
483 if (! seginfo->frchainP)
484 seginfo->frchainP = frchain_now;
485 return secptr;
486}
487
488void
489subseg_set (secptr, subseg)
490 segT secptr;
491 subsegT subseg;
492{
493 if (! (secptr == now_seg && subseg == now_subseg))
494 subseg_set_rest (secptr, subseg);
495 mri_common_symbol = NULL;
496}
497
498#ifndef obj_sec_sym_ok_for_reloc
499#define obj_sec_sym_ok_for_reloc(SEC) 0
500#endif
501
502/* Get the gas information we are storing for a section. */
503
504segment_info_type *
505seg_info (sec)
506 segT sec;
507{
508 if (sec == bfd_abs_section_ptr)
509 return abs_seg_info;
510 else if (sec == bfd_und_section_ptr)
511 return und_seg_info;
512 else
513 return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
514}
515
516symbolS *
517section_symbol (sec)
518 segT sec;
519{
520 segment_info_type *seginfo = seg_info (sec);
521 symbolS *s;
522
523 if (seginfo == 0)
524 abort ();
525 if (seginfo->sym)
526 return seginfo->sym;
527
528#ifndef EMIT_SECTION_SYMBOLS
529#define EMIT_SECTION_SYMBOLS 1
530#endif
531
532 if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
533 {
534 /* Here we know it won't be going into the symbol table. */
535 s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
536 }
537 else
538 {
539 s = symbol_find_base (sec->symbol->name, 0);
540 if (s == NULL)
541 s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
542 else
543 {
544 if (S_GET_SEGMENT (s) == undefined_section)
545 {
546 S_SET_SEGMENT (s, sec);
547 symbol_set_frag (s, &zero_address_frag);
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))
556 symbol_set_bfdsym (s, sec->symbol);
557 else
558 symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
559
560 seginfo->sym = s;
561 return s;
562}
563
564#endif /* BFD_ASSEMBLER */
565
566/* Return whether the specified segment is thought to hold text. */
567
568#ifndef BFD_ASSEMBLER
569const char * const nontext_section_names[] = {
570 ".eh_frame",
571 ".gcc_except_table",
572#ifdef OBJ_COFF
573#ifndef COFF_LONG_SECTION_NAMES
574 ".eh_fram",
575 ".gcc_exc",
576#endif
577#endif
578 NULL
579};
580#endif /* ! BFD_ASSEMBLER */
581
582int
583subseg_text_p (sec)
584 segT sec;
585{
586#ifdef BFD_ASSEMBLER
587 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
588#else /* ! BFD_ASSEMBLER */
589 const char * const *p;
590
591 if (sec == data_section || sec == bss_section || sec == absolute_section)
592 return 0;
593
594 for (p = nontext_section_names; *p != NULL; ++p)
595 {
596 if (strcmp (segment_name (sec), *p) == 0)
597 return 0;
598
599#ifdef obj_segment_name
600 if (strcmp (obj_segment_name (sec), *p) == 0)
601 return 0;
602#endif
603 }
604
605 return 1;
606
607#endif /* ! BFD_ASSEMBLER */
608}
609
610void
611subsegs_print_statistics (file)
612 FILE *file;
613{
614 frchainS *frchp;
615 fprintf (file, "frag chains:\n");
616 for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
617 {
618 int count = 0;
619 fragS *fragp;
620
621 /* If frch_subseg is non-zero, it's probably been chained onto
622 the end of a previous subsection. Don't count it again. */
623 if (frchp->frch_subseg != 0)
624 continue;
625
626 /* Skip gas-internal sections. */
627 if (segment_name (frchp->frch_seg)[0] == '*')
628 continue;
629
630 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
631 {
632#if 0
633 switch (fragp->fr_type)
634 {
635 case rs_fill:
636 fprintf (file, "f"); break;
637 case rs_align:
638 fprintf (file, "a"); break;
639 case rs_align_code:
640 fprintf (file, "c"); break;
641 case rs_org:
642 fprintf (file, "o"); break;
643 case rs_machine_dependent:
644 fprintf (file, "m"); break;
645 case rs_space:
646 fprintf (file, "s"); break;
647 case 0:
648 fprintf (file, "0"); break;
649 default:
650 fprintf (file, "?"); break;
651 }
652#endif
653 count++;
654 }
655 fprintf (file, "\n");
656 fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
657 segment_name (frchp->frch_seg), count);
658 }
659}
660
661/* end of subsegs.c */
Note: See TracBrowser for help on using the repository browser.