* subsegs.c (abs_seg_info, und_seg_info): Define if BFD_ASSEMBLER.
[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, 675 Mass Ave, Cambridge, MA 02139, 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 #ifndef BFD_ASSEMBLER
33 #ifdef MANY_SEGMENTS
34 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
35
36 #else
37 /* Commented in "subsegs.h". */
38 frchainS *data0_frchainP, *bss0_frchainP;
39
40 #endif /* MANY_SEGMENTS */
41 char *const seg_name[] =
42 {
43   "absolute",
44 #ifdef MANY_SEGMENTS
45   "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9",
46 #else
47   "text",
48   "data",
49   "bss",
50 #endif /* MANY_SEGMENTS */
51   "unknown",
52   "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
53   "expr",
54   "debug",
55   "transfert vector preload",
56   "transfert vector postload",
57   "register",
58   "",
59 };                              /* Used by error reporters, dumpers etc. */
60 #else /* BFD_ASSEMBLER */
61
62 /* Gas segment information for bfd_abs_section_ptr and
63    bfd_und_section_ptr.  */
64 static segment_info_type *abs_seg_info;
65 static segment_info_type *und_seg_info;
66
67 #endif /* BFD_ASSEMBLER */
68
69 static void subseg_set_rest PARAMS ((segT, subsegT));
70 \f
71 void
72 subsegs_begin ()
73 {
74   /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
75 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
76   know (SEG_ABSOLUTE == 0);
77   know (SEG_TEXT == 1);
78   know (SEG_DATA == 2);
79   know (SEG_BSS == 3);
80   know (SEG_UNKNOWN == 4);
81   know (SEG_GOOF == 5);
82   know (SEG_EXPR == 6);
83   know (SEG_DEBUG == 7);
84   know (SEG_NTV == 8);
85   know (SEG_PTV == 9);
86   know (SEG_REGISTER == 10);
87   know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
88 #endif
89
90   obstack_begin (&frags, 5000);
91   frchain_root = NULL;
92   frchain_now = NULL;           /* Warn new_subseg() that we are booting. */
93   /* Fake up 1st frag.  It won't be used=> is ok if obstack...
94      pads the end of it for alignment. */
95   frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG);
96   memset (frag_now, 0, SIZEOF_STRUCT_FRAG);
97
98 #ifndef BFD_ASSEMBLER
99   /* This 1st frag will not be in any frchain.
100      We simply give subseg_new somewhere to scribble. */
101   now_subseg = 42;              /* Lie for 1st call to subseg_new. */
102 #ifdef MANY_SEGMENTS
103   {
104     int i;
105     for (i = SEG_E0; i < SEG_UNKNOWN; i++)
106       {
107         subseg_set (i, 0);
108         segment_info[i].frchainP = frchain_now;
109       }
110   }
111 #else
112   subseg_set (SEG_DATA, 0);     /* .data 0 */
113   data0_frchainP = frchain_now;
114
115   subseg_set (SEG_BSS, 0);
116   bss0_frchainP = frchain_now;
117
118 #endif /* ! MANY_SEGMENTS */
119 #endif /* ! BFD_ASSEMBLER */
120
121 }
122 \f
123 /*
124  *                      subseg_change()
125  *
126  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
127  * subsegment. If we are already in the correct subsegment, change nothing.
128  * This is used eg as a worker for subseg_set [which does make a new frag_now]
129  * and for changing segments after we have read the source. We construct eg
130  * fixSs even after the source file is read, so we do have to keep the
131  * segment context correct.
132  */
133 void
134 subseg_change (seg, subseg)
135      register segT seg;
136      register int subseg;
137 {
138   now_seg = seg;
139   now_subseg = subseg;
140
141 #ifdef BFD_ASSEMBLER
142   {
143     segment_info_type *seginfo;
144     seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
145     if (! seginfo)
146       {
147         seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
148         if (! seginfo)
149           abort ();
150         seginfo->fix_root = NULL;
151         seginfo->fix_tail = NULL;
152         seginfo->bfd_section = seg;
153         seginfo->sym = 0;
154         if (seg == bfd_abs_section_ptr)
155           abs_seg_info = seginfo;
156         else if (seg == bfd_und_section_ptr)
157           und_seg_info = seginfo;
158         else
159           bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
160       }
161   }
162 #else
163 #ifdef MANY_SEGMENTS
164   seg_fix_rootP = &segment_info[seg].fix_root;
165   seg_fix_tailP = &segment_info[seg].fix_tail;
166 #else
167   if (seg == SEG_DATA)
168     {
169       seg_fix_rootP = &data_fix_root;
170       seg_fix_tailP = &data_fix_tail;
171     }
172   else if (seg == SEG_TEXT)
173     {
174       seg_fix_rootP = &text_fix_root;
175       seg_fix_tailP = &text_fix_tail;
176     }
177   else
178     {
179       know (seg == SEG_BSS);
180       seg_fix_rootP = &bss_fix_root;
181       seg_fix_tailP = &bss_fix_tail;
182     }
183
184 #endif
185 #endif
186 }
187 \f
188 static void
189 subseg_set_rest (seg, subseg)
190      segT seg;
191      subsegT subseg;
192 {
193   long tmp;                     /* JF for obstack alignment hacking */
194   register frchainS *frcP;      /* crawl frchain chain */
195   register frchainS **lastPP;   /* address of last pointer */
196   frchainS *newP;               /* address of new frchain */
197   register fragS *former_last_fragP;
198   register fragS *new_fragP;
199
200   if (frag_now)         /* If not bootstrapping. */
201     {
202       frag_now->fr_fix = (char*) obstack_next_free (&frags) - frag_now->fr_literal;
203       frag_wane (frag_now);     /* Close off any frag in old subseg. */
204     }
205   /*
206    * It would be nice to keep an obstack for each subsegment, if we swap
207    * subsegments a lot. Hence we would have much fewer frag_wanes().
208    */
209   {
210     obstack_finish (&frags);
211     /*
212      * If we don't do the above, the next object we put on obstack frags
213      * will appear to start at the fr_literal of the current frag.
214      * Also, above ensures that the next object will begin on a
215      * address that is aligned correctly for the engine that runs
216      * this program.
217      */
218   }
219   subseg_change (seg, (int) subseg);
220   /*
221    * Attempt to find or make a frchain for that sub seg.
222    * Crawl along chain of frchainSs, begins @ frchain_root.
223    * If we need to make a frchainS, link it into correct
224    * position of chain rooted in frchain_root.
225    */
226   for (frcP = *(lastPP = &frchain_root);
227        frcP && (int) (frcP->frch_seg) <= (int) seg;
228        frcP = *(lastPP = &frcP->frch_next))
229     {
230       if ((int) (frcP->frch_seg) == (int) seg
231           && frcP->frch_subseg >= subseg)
232         {
233           break;
234         }
235     }
236   /*
237    * frcP:              Address of the 1st frchainS in correct segment with
238    *            frch_subseg >= subseg.
239    *            We want to either use this frchainS, or we want
240    *            to insert a new frchainS just before it.
241    *
242    *            If frcP==NULL, then we are at the end of the chain
243    *            of frchainS-s. A NULL frcP means we fell off the end
244    *            of the chain looking for a
245    *            frch_subseg >= subseg, so we
246    *            must make a new frchainS.
247    *
248    *            If we ever maintain a pointer to
249    *            the last frchainS in the chain, we change that pointer
250    *            ONLY when frcP==NULL.
251    *
252    * lastPP:    Address of the pointer with value frcP;
253    *            Never NULL.
254    *            May point to frchain_root.
255    *
256    */
257   if (!frcP
258       || ((int) (frcP->frch_seg) > (int) seg
259           || frcP->frch_subseg > subseg))       /* Kinky logic only works with 2 segments. */
260     {
261       /*
262        * This should be the only code that creates a frchainS.
263        */
264       newP = (frchainS *) obstack_alloc (&frags, sizeof (frchainS));
265       memset (newP, 0, sizeof (frchainS));
266       /* This begines on a good boundary because a obstack_done()
267          preceeded it.  It implies an obstack_done(), so we expect
268          the next object allocated to begin on a correct boundary. */
269       *lastPP = newP;
270       newP->frch_next = frcP;   /* perhaps NULL */
271       (frcP = newP)->frch_subseg = subseg;
272       newP->frch_seg = seg;
273       newP->frch_last = NULL;
274 #ifdef BFD_ASSEMBLER
275       newP->fix_root = NULL;
276       newP->fix_tail = NULL;
277 #endif
278     }
279   /*
280    * Here with frcP ->ing to the frchainS for subseg.
281    */
282   frchain_now = frcP;
283   /*
284    * Make a fresh frag for the subsegment.
285    */
286   /* We expect this to happen on a correct boundary since it was
287      proceeded by a obstack_done(). */
288   tmp = obstack_alignment_mask (&frags);        /* JF disable alignment */
289   obstack_alignment_mask (&frags) = 0;
290   frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG);
291   memset (frag_now, 0, SIZEOF_STRUCT_FRAG);
292   obstack_alignment_mask (&frags) = tmp;
293   /* But we want any more chars to come immediately after the
294      structure we just made. */
295   new_fragP = frag_now;
296   new_fragP->fr_next = NULL;
297   /*
298    * Append new frag to current frchain.
299    */
300   former_last_fragP = frcP->frch_last;
301   if (former_last_fragP)
302     {
303       know (former_last_fragP->fr_next == NULL);
304       know (frchain_now->frch_root);
305       former_last_fragP->fr_next = new_fragP;
306     }
307   else
308     {
309       frcP->frch_root = new_fragP;
310     }
311   frcP->frch_last = new_fragP;
312 }
313
314 /*
315  *                      subseg_set(segT, subsegT)
316  *
317  * If you attempt to change to the current subsegment, nothing happens.
318  *
319  * In:  segT, subsegT code for new subsegment.
320  *      frag_now -> incomplete frag for current subsegment.
321  *      If frag_now==NULL, then there is no old, incomplete frag, so
322  *      the old frag is not closed off.
323  *
324  * Out: now_subseg, now_seg updated.
325  *      Frchain_now points to the (possibly new) struct frchain for this
326  *      sub-segment.
327  *      Frchain_root updated if needed.
328  */
329
330 #ifndef BFD_ASSEMBLER
331
332 segT
333 subseg_new (segname, subseg)
334      const char *segname;
335      subsegT subseg;
336 {
337   int i;
338
339   for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
340     {
341       const char *s;
342
343       s = segment_name ((segT) i);
344       if (strcmp (segname, s) == 0
345           || (segname[0] == '.'
346               && strcmp (segname + 1, s) == 0))
347         {
348           subseg_set ((segT) i, subseg);
349           return (segT) i;
350         }
351 #ifdef obj_segment_name
352       s = obj_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 #endif
361     }
362
363 #ifdef obj_add_segment
364   {
365     segT new_seg;
366     new_seg = obj_add_segment (segname);
367     subseg_set (new_seg, subseg);
368     return new_seg;
369   }
370 #else
371   as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname);
372   return now_seg;
373 #endif
374 }
375
376 void
377 subseg_set (seg, subseg)        /* begin assembly for a new sub-segment */
378      register segT seg;         /* SEG_DATA or SEG_TEXT */
379      register subsegT subseg;
380 {
381 #ifndef MANY_SEGMENTS
382   know (seg == SEG_DATA || seg == SEG_TEXT || seg == SEG_BSS);
383 #endif
384
385   if (seg != now_seg || subseg != now_subseg)
386     {                           /* we just changed sub-segments */
387       subseg_set_rest (seg, subseg);
388     }
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 ((char *) 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 }
483
484 #ifndef obj_sec_sym_ok_for_reloc
485 #define obj_sec_sym_ok_for_reloc(SEC)   0
486 #endif
487
488 /* Get the gas information we are storing for a section.  */
489
490 segment_info_type *
491 seg_info (sec)
492      segT sec;
493 {
494   if (sec == bfd_abs_section_ptr)
495     return abs_seg_info;
496   else if (sec == bfd_und_section_ptr)
497     return und_seg_info;
498   else
499     return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
500 }
501
502 symbolS *
503 section_symbol (sec)
504      segT sec;
505 {
506   segment_info_type *seginfo = seg_info (sec);
507   symbolS *s;
508
509   if (seginfo == 0)
510     abort ();
511   if (seginfo->sym)
512     return seginfo->sym;
513   s = symbol_find (sec->name);
514   if (!s)
515     {
516       s = symbol_new (sec->name, sec, 0, &zero_address_frag);
517       S_CLEAR_EXTERNAL (s);
518
519       /* Use the BFD section symbol, if possible.  */
520       if (obj_sec_sym_ok_for_reloc (sec))
521         s->bsym = sec->symbol;
522     }
523   seginfo->sym = s;
524   return s;
525 }
526
527 #endif /* BFD_ASSEMBLER */
528
529 /* end of subsegs.c */