Add support for storing local symbols in a small structure to save
[external/binutils.git] / gas / subsegs.c
1 /* subsegs.c - subsegments -
2    Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999
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
31 frchainS *frchain_root, *frchain_now;
32
33 static struct obstack frchains;
34
35 #ifndef BFD_ASSEMBLER
36 #ifdef MANY_SEGMENTS
37 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
38
39 #else
40 /* Commented in "subsegs.h". */
41 frchainS *data0_frchainP, *bss0_frchainP;
42
43 #endif /* MANY_SEGMENTS */
44 char 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.  */
70 static segment_info_type *abs_seg_info;
71 static segment_info_type *und_seg_info;
72
73 #endif /* BFD_ASSEMBLER */
74
75 static void subseg_set_rest PARAMS ((segT, subsegT));
76
77 static fragS dummy_frag;
78
79 static frchainS absolute_frchain;
80 \f
81 void
82 subsegs_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  */
150 void
151 subseg_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
207 static void
208 subseg_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
340 segT
341 subseg_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
384 void
385 subseg_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
405 segT
406 subseg_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
453 segT
454 subseg_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.  */
471 segT
472 subseg_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
487 void
488 subseg_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
503 segment_info_type *
504 seg_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
515 symbolS *
516 section_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);
550               symbol_set_frag (s, &zero_address_frag);
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))
559     symbol_set_bfdsym (s, sec->symbol);
560
561   seginfo->sym = s;
562   return s;
563 }
564
565 #endif /* BFD_ASSEMBLER */
566
567 void
568 subsegs_print_statistics (file)
569      FILE *file;
570 {
571   frchainS *frchp;
572   fprintf (file, "frag chains:\n");
573   for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
574     {
575       int count = 0;
576       fragS *fragp;
577
578       /* If frch_subseg is non-zero, it's probably been chained onto
579          the end of a previous subsection.  Don't count it again.  */
580       if (frchp->frch_subseg != 0)
581         continue;
582
583       /* Skip gas-internal sections.  */
584       if (segment_name (frchp->frch_seg)[0] == '*')
585         continue;
586
587       for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
588         {
589 #if 0
590           switch (fragp->fr_type)
591             {
592             case rs_fill:
593               fprintf (file, "f"); break;
594             case rs_align:
595               fprintf (file, "a"); break;
596             case rs_align_code:
597               fprintf (file, "c"); break;
598             case rs_org:
599               fprintf (file, "o"); break;
600             case rs_machine_dependent:
601               fprintf (file, "m"); break;
602             case rs_space:
603               fprintf (file, "s"); break;
604             case 0:
605               fprintf (file, "0"); break;
606             default:
607               fprintf (file, "?"); break;
608             }
609 #endif
610           count++;
611         }
612       fprintf (file, "\n");
613       fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
614                segment_name (frchp->frch_seg), count);
615     }
616 }
617
618 /* end of subsegs.c */