]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/subsegs.c
2005-01-27 Andrew Cagney <cagney@gnu.org>
[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,
22fe14ad 3 1999, 2000, 2002, 2004
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
24361518 73static void subseg_set_rest (segT, subsegT);
252b5132
RH
74
75static fragS dummy_frag;
76
77static frchainS absolute_frchain;
78\f
79void
24361518 80subsegs_begin (void)
252b5132
RH
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
24361518 149subseg_change (register segT seg, register int subseg)
252b5132
RH
150{
151 now_seg = seg;
152 now_subseg = subseg;
153
154 if (now_seg == absolute_section)
155 return;
156
157#ifdef BFD_ASSEMBLER
158 {
159 segment_info_type *seginfo;
160 seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
161 if (! seginfo)
162 {
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);
175 }
176 }
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)
183 {
184 seg_fix_rootP = &data_fix_root;
185 seg_fix_tailP = &data_fix_tail;
186 }
187 else if (seg == SEG_TEXT)
188 {
189 seg_fix_rootP = &text_fix_root;
190 seg_fix_tailP = &text_fix_tail;
191 }
192 else
193 {
194 know (seg == SEG_BSS);
195 seg_fix_rootP = &bss_fix_root;
196 seg_fix_tailP = &bss_fix_tail;
197 }
198
199#endif
200#endif
201}
202\f
203static void
24361518 204subseg_set_rest (segT seg, subsegT subseg)
252b5132
RH
205{
206 register frchainS *frcP; /* crawl frchain chain */
207 register frchainS **lastPP; /* address of last pointer */
208 frchainS *newP; /* address of new frchain */
209
210 mri_common_symbol = NULL;
211
212 if (frag_now && frchain_now)
213 frchain_now->frch_frag_now = frag_now;
214
215 assert (frchain_now == 0
216 || now_seg == undefined_section
217 || now_seg == absolute_section
218 || frchain_now->frch_last == frag_now);
219
220 subseg_change (seg, (int) subseg);
221
222 if (seg == absolute_section)
223 {
224 frchain_now = &absolute_frchain;
225 frag_now = &zero_address_frag;
226 return;
227 }
228
229 assert (frchain_now == 0
230 || now_seg == undefined_section
231 || frchain_now->frch_last == frag_now);
232
233 /*
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.
238 */
239 for (frcP = *(lastPP = &frchain_root);
240 frcP && frcP->frch_seg <= seg;
241 frcP = *(lastPP = &frcP->frch_next))
242 {
243 if (frcP->frch_seg == seg
244 && frcP->frch_subseg >= subseg)
245 {
246 break;
247 }
248 }
249 /*
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.
254 *
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.
260 *
261 * If we ever maintain a pointer to
262 * the last frchainS in the chain, we change that pointer
263 * ONLY when frcP==NULL.
264 *
265 * lastPP: Address of the pointer with value frcP;
266 * Never NULL.
267 * May point to frchain_root.
268 *
269 */
270 if (!frcP
271 || (frcP->frch_seg > seg
f0e652b4 272 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
252b5132
RH
273 {
274 /*
275 * This should be the only code that creates a frchainS.
276 */
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;
290
291 newP->frch_root = newP->frch_last = newP->frch_frag_now;
292
293 *lastPP = newP;
294 newP->frch_next = frcP; /* perhaps NULL */
295
296#ifdef BFD_ASSEMBLER
297 {
298 segment_info_type *seginfo;
299 seginfo = seg_info (seg);
300 if (seginfo && seginfo->frchainP == frcP)
301 seginfo->frchainP = newP;
302 }
303#endif
f0e652b4 304
252b5132
RH
305 frcP = newP;
306 }
307 /*
308 * Here with frcP pointing to the frchainS for subseg.
309 */
310 frchain_now = frcP;
311 frag_now = frcP->frch_frag_now;
312
313 assert (frchain_now->frch_last == frag_now);
314}
315
316/*
317 * subseg_set(segT, subsegT)
318 *
319 * If you attempt to change to the current subsegment, nothing happens.
320 *
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.
325 *
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.
330 */
331
332#ifndef BFD_ASSEMBLER
333
334segT
335subseg_new (segname, subseg)
336 const char *segname;
337 subsegT subseg;
338{
339 int i;
340
341 for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
342 {
343 const char *s;
344
345 s = segment_name ((segT) i);
346 if (strcmp (segname, s) == 0
347 || (segname[0] == '.'
348 && strcmp (segname + 1, s) == 0))
349 {
350 subseg_set ((segT) i, subseg);
351 return (segT) i;
352 }
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))
358 {
359 subseg_set ((segT) i, subseg);
360 return (segT) i;
361 }
362#endif
363 }
364
365#ifdef obj_add_segment
366 {
367 segT new_seg;
368 new_seg = obj_add_segment (segname);
369 subseg_set (new_seg, subseg);
370 return new_seg;
371 }
372#else
0e389e77 373 as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname);
252b5132
RH
374 return now_seg;
375#endif
376}
377
378void
379subseg_set (seg, subseg) /* begin assembly for a new sub-segment */
380 register segT seg; /* SEG_DATA or SEG_TEXT */
381 register subsegT subseg;
382{
383#ifndef MANY_SEGMENTS
384 know (seg == SEG_DATA
385 || seg == SEG_TEXT
386 || seg == SEG_BSS
387 || seg == SEG_ABSOLUTE);
388#endif
389
390 if (seg != now_seg || subseg != now_subseg)
391 { /* we just changed sub-segments */
392 subseg_set_rest (seg, subseg);
393 }
394 mri_common_symbol = NULL;
395}
396
397#else /* BFD_ASSEMBLER */
398
399segT
24361518 400subseg_get (const char *segname, int force_new)
252b5132
RH
401{
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);
407
408 if (!force_new
409 && now_seg_name
410 && (now_seg_name == segname
411 || !strcmp (now_seg_name, segname)))
412 return now_seg;
413
414 if (!force_new)
415 secptr = bfd_make_section_old_way (stdoutput, segname);
416 else
417 secptr = bfd_make_section_anyway (stdoutput, segname);
418
2f89ff8d
L
419#ifdef obj_sec_set_private_data
420 obj_sec_set_private_data (stdoutput, secptr);
421#endif
422
252b5132
RH
423 seginfo = seg_info (secptr);
424 if (! seginfo)
425 {
426 /* Check whether output_section is set first because secptr may
546c73f9 427 be bfd_abs_section_ptr. */
252b5132
RH
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;
445 }
446 return secptr;
447}
448
449segT
24361518 450subseg_new (const char *segname, subsegT subseg)
252b5132
RH
451{
452 segT secptr;
453 segment_info_type *seginfo;
454
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;
461}
462
463/* Like subseg_new, except a new section is always created, even if
464 a section with that name already exists. */
465segT
24361518 466subseg_force_new (const char *segname, subsegT subseg)
252b5132
RH
467{
468 segT secptr;
469 segment_info_type *seginfo;
470
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;
477}
478
479void
24361518 480subseg_set (segT secptr, subsegT subseg)
252b5132
RH
481{
482 if (! (secptr == now_seg && subseg == now_subseg))
483 subseg_set_rest (secptr, subseg);
484 mri_common_symbol = NULL;
485}
486
487#ifndef obj_sec_sym_ok_for_reloc
488#define obj_sec_sym_ok_for_reloc(SEC) 0
489#endif
490
491/* Get the gas information we are storing for a section. */
492
493segment_info_type *
24361518 494seg_info (segT sec)
252b5132
RH
495{
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);
502}
503
504symbolS *
24361518 505section_symbol (segT sec)
252b5132
RH
506{
507 segment_info_type *seginfo = seg_info (sec);
508 symbolS *s;
509
510 if (seginfo == 0)
511 abort ();
512 if (seginfo->sym)
513 return seginfo->sym;
514
515#ifndef EMIT_SECTION_SYMBOLS
516#define EMIT_SECTION_SYMBOLS 1
517#endif
518
a161fe53 519 if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
252b5132
RH
520 {
521 /* Here we know it won't be going into the symbol table. */
546c73f9 522 s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
252b5132
RH
523 }
524 else
525 {
90c1602c 526 segT seg;
546c73f9 527 s = symbol_find_base (sec->symbol->name, 0);
22fe14ad
NC
528 /* We have to make sure it is the right symbol when we
529 have multiple sections with the same section name. */
90c1602c
L
530 if (s == NULL
531 || ((seg = S_GET_SEGMENT (s)) != sec
532 && seg != undefined_section))
546c73f9 533 s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
90c1602c 534 else if (seg == undefined_section)
252b5132 535 {
90c1602c
L
536 S_SET_SEGMENT (s, sec);
537 symbol_set_frag (s, &zero_address_frag);
252b5132
RH
538 }
539 }
540
541 S_CLEAR_EXTERNAL (s);
542
543 /* Use the BFD section symbol, if possible. */
544 if (obj_sec_sym_ok_for_reloc (sec))
49309057 545 symbol_set_bfdsym (s, sec->symbol);
a161fe53
AM
546 else
547 symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
252b5132
RH
548
549 seginfo->sym = s;
550 return s;
551}
552
553#endif /* BFD_ASSEMBLER */
554
b9e57a38
ILT
555/* Return whether the specified segment is thought to hold text. */
556
be2acf27 557#ifndef BFD_ASSEMBLER
ef99799a 558const char * const nontext_section_names[] = {
be2acf27
ILT
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
568};
569#endif /* ! BFD_ASSEMBLER */
570
b9e57a38 571int
24361518 572subseg_text_p (segT sec)
b9e57a38
ILT
573{
574#ifdef BFD_ASSEMBLER
575 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
be2acf27
ILT
576#else /* ! BFD_ASSEMBLER */
577 const char * const *p;
578
ebeb9253 579 if (sec == data_section || sec == bss_section || sec == absolute_section)
264d6861 580 return 0;
be2acf27
ILT
581
582 for (p = nontext_section_names; *p != NULL; ++p)
583 {
584 if (strcmp (segment_name (sec), *p) == 0)
264d6861 585 return 0;
be2acf27
ILT
586
587#ifdef obj_segment_name
588 if (strcmp (obj_segment_name (sec), *p) == 0)
264d6861 589 return 0;
b9e57a38 590#endif
be2acf27
ILT
591 }
592
264d6861 593 return 1;
be2acf27
ILT
594
595#endif /* ! BFD_ASSEMBLER */
b9e57a38
ILT
596}
597
252b5132 598void
24361518 599subsegs_print_statistics (FILE *file)
252b5132
RH
600{
601 frchainS *frchp;
602 fprintf (file, "frag chains:\n");
603 for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
604 {
605 int count = 0;
606 fragS *fragp;
607
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;
612
613 /* Skip gas-internal sections. */
614 if (segment_name (frchp->frch_seg)[0] == '*')
615 continue;
616
617 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
618 {
252b5132
RH
619 count++;
620 }
621 fprintf (file, "\n");
03e83a45 622 fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
252b5132
RH
623 segment_name (frchp->frch_seg), count);
624 }
625}
626
627/* end of subsegs.c */