This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / gas / subsegs.c
1 /* subsegs.c - subsegments -
2    Copyright (C) 1987, 1990, 1991, 1992, 1993, 1994
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
19    the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 /*
22  * Segments & sub-segments.
23  */
24
25 #include "as.h"
26
27 #include "subsegs.h"
28 #include "obstack.h"
29
30 frchainS *frchain_root, *frchain_now;
31
32 static struct obstack frchains;
33
34 #ifndef BFD_ASSEMBLER
35 #ifdef MANY_SEGMENTS
36 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
37
38 #else
39 /* Commented in "subsegs.h". */
40 frchainS *data0_frchainP, *bss0_frchainP;
41
42 #endif /* MANY_SEGMENTS */
43 char const *const seg_name[] =
44 {
45   "absolute",
46 #ifdef MANY_SEGMENTS
47   "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9",
48 #else
49   "text",
50   "data",
51   "bss",
52 #endif /* MANY_SEGMENTS */
53   "unknown",
54   "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
55   "expr",
56   "debug",
57   "transfert vector preload",
58   "transfert vector postload",
59   "register",
60   "",
61 };                              /* Used by error reporters, dumpers etc. */
62 #else /* BFD_ASSEMBLER */
63
64 /* Gas segment information for bfd_abs_section_ptr and
65    bfd_und_section_ptr.  */
66 static segment_info_type *abs_seg_info;
67 static segment_info_type *und_seg_info;
68
69 #endif /* BFD_ASSEMBLER */
70
71 static void subseg_set_rest PARAMS ((segT, subsegT));
72
73 static fragS dummy_frag;
74
75 static frchainS absolute_frchain;
76 \f
77 void
78 subsegs_begin ()
79 {
80   /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
81 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
82   know (SEG_ABSOLUTE == 0);
83   know (SEG_TEXT == 1);
84   know (SEG_DATA == 2);
85   know (SEG_BSS == 3);
86   know (SEG_UNKNOWN == 4);
87   know (SEG_GOOF == 5);
88   know (SEG_EXPR == 6);
89   know (SEG_DEBUG == 7);
90   know (SEG_NTV == 8);
91   know (SEG_PTV == 9);
92   know (SEG_REGISTER == 10);
93   know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
94 #endif
95
96   obstack_begin (&frchains, chunksize);
97 #if __GNUC__ >= 2
98   obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
99 #endif
100
101   frchain_root = NULL;
102   frchain_now = NULL;           /* Warn new_subseg() that we are booting. */
103
104   frag_now = &dummy_frag;
105
106 #ifndef BFD_ASSEMBLER
107   now_subseg = 42;              /* Lie for 1st call to subseg_new. */
108 #ifdef MANY_SEGMENTS
109   {
110     int i;
111     for (i = SEG_E0; i < SEG_UNKNOWN; i++)
112       {
113         subseg_set (i, 0);
114         segment_info[i].frchainP = frchain_now;
115       }
116   }
117 #else
118   subseg_set (SEG_DATA, 0);     /* .data 0 */
119   data0_frchainP = frchain_now;
120
121   subseg_set (SEG_BSS, 0);
122   bss0_frchainP = frchain_now;
123
124 #endif /* ! MANY_SEGMENTS */
125 #endif /* ! BFD_ASSEMBLER */
126
127   absolute_frchain.frch_seg = absolute_section;
128   absolute_frchain.frch_subseg = 0;
129   absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
130   absolute_frchain.frch_frag_now = &zero_address_frag;
131   absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
132 }
133 \f
134 /*
135  *                      subseg_change()
136  *
137  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
138  * subsegment. If we are already in the correct subsegment, change nothing.
139  * This is used eg as a worker for subseg_set [which does make a new frag_now]
140  * and for changing segments after we have read the source. We construct eg
141  * fixSs even after the source file is read, so we do have to keep the
142  * segment context correct.
143  */
144 void
145 subseg_change (seg, subseg)
146      register segT seg;
147      register int subseg;
148 {
149   now_seg = seg;
150   now_subseg = subseg;
151
152   if (now_seg == absolute_section)
153     return;
154
155 #ifdef BFD_ASSEMBLER
156   {
157     segment_info_type *seginfo;
158     seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
159     if (! seginfo)
160       {
161         seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
162         memset ((PTR) seginfo, 0, sizeof (*seginfo));
163         seginfo->fix_root = NULL;
164         seginfo->fix_tail = NULL;
165         seginfo->bfd_section = seg;
166         seginfo->sym = 0;
167         if (seg == bfd_abs_section_ptr)
168           abs_seg_info = seginfo;
169         else if (seg == bfd_und_section_ptr)
170           und_seg_info = seginfo;
171         else
172           bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
173       }
174   }
175 #else
176 #ifdef MANY_SEGMENTS
177   seg_fix_rootP = &segment_info[seg].fix_root;
178   seg_fix_tailP = &segment_info[seg].fix_tail;
179 #else
180   if (seg == SEG_DATA)
181     {
182       seg_fix_rootP = &data_fix_root;
183       seg_fix_tailP = &data_fix_tail;
184     }
185   else if (seg == SEG_TEXT)
186     {
187       seg_fix_rootP = &text_fix_root;
188       seg_fix_tailP = &text_fix_tail;
189     }
190   else
191     {
192       know (seg == SEG_BSS);
193       seg_fix_rootP = &bss_fix_root;
194       seg_fix_tailP = &bss_fix_tail;
195     }
196
197 #endif
198 #endif
199 }
200 \f
201 static void
202 subseg_set_rest (seg, subseg)
203      segT seg;
204      subsegT subseg;
205 {
206   long tmp;                     /* JF for obstack alignment hacking */
207   register frchainS *frcP;      /* crawl frchain chain */
208   register frchainS **lastPP;   /* address of last pointer */
209   frchainS *newP;               /* address of new frchain */
210   register fragS *former_last_fragP;
211   register fragS *new_fragP;
212
213   mri_common_symbol = NULL;
214
215   if (frag_now && frchain_now)
216     frchain_now->frch_frag_now = frag_now;
217
218   assert (frchain_now == 0
219           || now_seg == undefined_section
220           || now_seg == absolute_section
221           || frchain_now->frch_last == frag_now);
222
223   subseg_change (seg, (int) subseg);
224
225   if (seg == absolute_section)
226     {
227       frchain_now = &absolute_frchain;
228       frag_now = &zero_address_frag;
229       return;
230     }
231
232   assert (frchain_now == 0
233           || now_seg == undefined_section
234           || frchain_now->frch_last == frag_now);
235
236   /*
237    * Attempt to find or make a frchain for that sub seg.
238    * Crawl along chain of frchainSs, begins @ frchain_root.
239    * If we need to make a frchainS, link it into correct
240    * position of chain rooted in frchain_root.
241    */
242   for (frcP = *(lastPP = &frchain_root);
243        frcP && frcP->frch_seg <= seg;
244        frcP = *(lastPP = &frcP->frch_next))
245     {
246       if (frcP->frch_seg == seg
247           && frcP->frch_subseg >= subseg)
248         {
249           break;
250         }
251     }
252   /*
253    * frcP:              Address of the 1st frchainS in correct segment with
254    *            frch_subseg >= subseg.
255    *            We want to either use this frchainS, or we want
256    *            to insert a new frchainS just before it.
257    *
258    *            If frcP==NULL, then we are at the end of the chain
259    *            of frchainS-s. A NULL frcP means we fell off the end
260    *            of the chain looking for a
261    *            frch_subseg >= subseg, so we
262    *            must make a new frchainS.
263    *
264    *            If we ever maintain a pointer to
265    *            the last frchainS in the chain, we change that pointer
266    *            ONLY when frcP==NULL.
267    *
268    * lastPP:    Address of the pointer with value frcP;
269    *            Never NULL.
270    *            May point to frchain_root.
271    *
272    */
273   if (!frcP
274       || (frcP->frch_seg > seg
275           || frcP->frch_subseg > subseg))       /* Kinky logic only works with 2 segments. */
276     {
277       /*
278        * This should be the only code that creates a frchainS.
279        */
280       extern fragS *frag_alloc ();
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, 5000);
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       frcP = newP;
300     }
301   /*
302    * Here with frcP pointing to the frchainS for subseg.
303    */
304   frchain_now = frcP;
305   frag_now = frcP->frch_frag_now;
306
307   assert (frchain_now->frch_last == frag_now);
308 }
309
310 /*
311  *                      subseg_set(segT, subsegT)
312  *
313  * If you attempt to change to the current subsegment, nothing happens.
314  *
315  * In:  segT, subsegT code for new subsegment.
316  *      frag_now -> incomplete frag for current subsegment.
317  *      If frag_now==NULL, then there is no old, incomplete frag, so
318  *      the old frag is not closed off.
319  *
320  * Out: now_subseg, now_seg updated.
321  *      Frchain_now points to the (possibly new) struct frchain for this
322  *      sub-segment.
323  *      Frchain_root updated if needed.
324  */
325
326 #ifndef BFD_ASSEMBLER
327
328 segT
329 subseg_new (segname, subseg)
330      const char *segname;
331      subsegT subseg;
332 {
333   int i;
334
335   for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
336     {
337       const char *s;
338
339       s = segment_name ((segT) i);
340       if (strcmp (segname, s) == 0
341           || (segname[0] == '.'
342               && strcmp (segname + 1, s) == 0))
343         {
344           subseg_set ((segT) i, subseg);
345           return (segT) i;
346         }
347 #ifdef obj_segment_name
348       s = obj_segment_name ((segT) i);
349       if (strcmp (segname, s) == 0
350           || (segname[0] == '.'
351               && strcmp (segname + 1, s) == 0))
352         {
353           subseg_set ((segT) i, subseg);
354           return (segT) i;
355         }
356 #endif
357     }
358
359 #ifdef obj_add_segment
360   {
361     segT new_seg;
362     new_seg = obj_add_segment (segname);
363     subseg_set (new_seg, subseg);
364     return new_seg;
365   }
366 #else
367   as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname);
368   return now_seg;
369 #endif
370 }
371
372 void
373 subseg_set (seg, subseg)        /* begin assembly for a new sub-segment */
374      register segT seg;         /* SEG_DATA or SEG_TEXT */
375      register subsegT subseg;
376 {
377 #ifndef MANY_SEGMENTS
378   know (seg == SEG_DATA
379         || seg == SEG_TEXT
380         || seg == SEG_BSS
381         || seg == SEG_ABSOLUTE);
382 #endif
383
384   if (seg != now_seg || subseg != now_subseg)
385     {                           /* we just changed sub-segments */
386       subseg_set_rest (seg, subseg);
387     }
388   mri_common_symbol = NULL;
389 }
390
391 #else /* BFD_ASSEMBLER */
392
393 segT
394 subseg_get (segname, force_new)
395      const char *segname;
396      int force_new;
397 {
398   segT secptr;
399   segment_info_type *seginfo;
400   const char *now_seg_name = (now_seg
401                               ? bfd_get_section_name (stdoutput, now_seg)
402                               : 0);
403
404   if (!force_new
405       && now_seg_name
406       && (now_seg_name == segname
407           || !strcmp (now_seg_name, segname)))
408     return now_seg;
409
410   if (!force_new)
411     secptr = bfd_make_section_old_way (stdoutput, segname);
412   else
413     secptr = bfd_make_section_anyway (stdoutput, segname);
414
415   seginfo = seg_info (secptr);
416   if (! seginfo)
417     {
418       /* Check whether output_section is set first because secptr may
419          be bfd_abs_section_ptr.  */
420       if (secptr->output_section != secptr)
421         secptr->output_section = secptr;
422       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
423       memset ((PTR) seginfo, 0, sizeof (*seginfo));
424       seginfo->fix_root = NULL;
425       seginfo->fix_tail = NULL;
426       seginfo->bfd_section = secptr;
427       if (secptr == bfd_abs_section_ptr)
428         abs_seg_info = seginfo;
429       else if (secptr == bfd_und_section_ptr)
430         und_seg_info = seginfo;
431       else
432         bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
433       seginfo->frchainP = NULL;
434       seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
435       seginfo->sym = NULL;
436       seginfo->dot = NULL;
437     }
438   return secptr;
439 }
440
441 segT
442 subseg_new (segname, subseg)
443      const char *segname;
444      subsegT subseg;
445 {
446   segT secptr;
447   segment_info_type *seginfo;
448
449   secptr = subseg_get (segname, 0);
450   subseg_set_rest (secptr, subseg);
451   seginfo = seg_info (secptr);
452   if (! seginfo->frchainP)
453     seginfo->frchainP = frchain_now;
454   return secptr;
455 }
456
457 /* Like subseg_new, except a new section is always created, even if
458    a section with that name already exists.  */
459 segT
460 subseg_force_new (segname, subseg)
461      const char *segname;
462      subsegT subseg;
463 {
464   segT secptr;
465   segment_info_type *seginfo;
466
467   secptr = subseg_get (segname, 1);
468   subseg_set_rest (secptr, subseg);
469   seginfo = seg_info (secptr);
470   if (! seginfo->frchainP)
471     seginfo->frchainP = frchain_now;
472   return secptr;
473 }
474
475 void
476 subseg_set (secptr, subseg)
477      segT secptr;
478      subsegT subseg;
479 {
480   if (! (secptr == now_seg && subseg == now_subseg))
481     subseg_set_rest (secptr, subseg);
482   mri_common_symbol = NULL;
483 }
484
485 #ifndef obj_sec_sym_ok_for_reloc
486 #define obj_sec_sym_ok_for_reloc(SEC)   0
487 #endif
488
489 /* Get the gas information we are storing for a section.  */
490
491 segment_info_type *
492 seg_info (sec)
493      segT sec;
494 {
495   if (sec == bfd_abs_section_ptr)
496     return abs_seg_info;
497   else if (sec == bfd_und_section_ptr)
498     return und_seg_info;
499   else
500     return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
501 }
502
503 symbolS *
504 section_symbol (sec)
505      segT sec;
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   s = symbol_find (sec->name);
515   if (!s)
516     {
517 #ifndef EMIT_SECTION_SYMBOLS
518 #define EMIT_SECTION_SYMBOLS 1
519 #endif
520
521       if (! EMIT_SECTION_SYMBOLS
522 #ifdef BFD_ASSEMBLER
523           && symbol_table_frozen
524 #endif
525           )
526         /* Here we know it won't be going into the symbol table.  */
527         s = symbol_create (sec->name, sec, 0, &zero_address_frag);
528       else
529         s = symbol_new (sec->name, sec, 0, &zero_address_frag);
530       S_CLEAR_EXTERNAL (s);
531
532       /* Use the BFD section symbol, if possible.  */
533       if (obj_sec_sym_ok_for_reloc (sec))
534         s->bsym = sec->symbol;
535     }
536   seginfo->sym = s;
537   return s;
538 }
539
540 #endif /* BFD_ASSEMBLER */
541
542 /* end of subsegs.c */